一次JS性能问题排查


一次JS性能问题排查

优化前

const getters = {
    treeTableData: state => {
        let hasTree = state.tableData && state.tableData.length > 0 && state.dataLink && Object.keys(state.dataLink).length > 0
        if (hasTree) {
            let epicList = Object.keys(state.dataLink)
            let needRemoveIssue = []
            epicList.forEach(epicId => {
                let children = []
                let childIdes = state.dataLink[epicId]
                if( childIdes ){
                    let epic = state.tableData.filter(item => item.key === epicId)[0]
                    for( let i =0;i< state.tableData.length;i++ ){
                        let item = state.tableData[i]
                        if(childIdes.indexOf(item.key) >-1 ){
                            children.push(item)
                            needRemoveIssue.push(item.key)
                        }
    
                    }                
                    epic.children = children
                }                
            })
            return state.tableData.filter(item => !needRemoveIssue.includes(item.key))
        }
        return state.tableData
    }
}

执行时间大概20s

第一次优化后

const getters = {
    treeTableData: state => {
        let hasTree = state.tableData && state.tableData.length > 0 && state.dataLink && Object.keys(state.dataLink).length > 0
        if (hasTree) {
            let epicList = Object.keys(state.dataLink)
            let needRemoveIssue = []
            epicList.forEach(epicId => {
                let children = []
                let epic = state.tableData.filter(item => item.key === epicId)[0]
                state.dataLink[epicId].forEach(childId => {
                    state.tableData.filter(item => item.key === childId).forEach(item => children.push(item))
                    needRemoveIssue.push(childId)
                })
                epic.children = children
            })
            return state.tableData.filter(item => !needRemoveIssue.includes(item.key))
        }
        return state.tableData
    }
}

执行时间300ms,但存在一个问题:children数组的元素顺序无法保证。

还得使用for循环遍历

第二次优化后

const getters = {
    treeTableData: state => {
        let hasTree = state.tableData && state.tableData.length > 0 && state.dataLink && Object.keys(state.dataLink).length > 0
        if (hasTree) {
            let epicList = Object.keys(state.dataLink)
            let needRemoveIssue = []
            let len = state.tableData.length
            epicList.forEach(epicId => {
                let children = []
                let childIdes = state.dataLink[epicId]
                if( childIdes ){
                    let epic = state.tableData.filter(item => item.key === epicId)[0]
                    for( let i =0;i< len;i++ ){
                        let item = state.tableData[i]
                        if(childIdes.includes(item.key)){
                            children.push(item)
                            needRemoveIssue.push(item.key)
                        }
                    }
                    epic.children = children
                }
            })
            return state.tableData.filter(item => !needRemoveIssue.includes(item.key))
        }
        return state.tableData
    }
}

执行时间:10s

第三次优化后

const getters = {
    treeTableData: state => {
        let hasTree = state.tableData && state.tableData.length > 0 && state.dataLink && Object.keys(state.dataLink).length > 0
        if (hasTree) {
            let epicList = Object.keys(state.dataLink)
            let needRemoveIssue = []
            let len = state.tableData.length
            let stateTable = state.tableData
            epicList.forEach(epicId => {
                let children = []
                let childIdes = state.dataLink[epicId]
                if( childIdes ){
                    let epic = stateTable.filter(item => item.key === epicId)[0]
                    for( let i =0;i< len;i++ ){
                        let item = stateTable[i]
                        if(childIdes.includes(item.key)){
                            children.push(item)
                            needRemoveIssue.push(item.key)
                        }
                    }
                    epic.children = children
                }
            })
            return state.tableData.filter(item => !needRemoveIssue.includes(item.key))
        }
        return state.tableData
    }
}

执行时间:150ms

总结

vuex的getters中state对象的访问开销太大,最好在使用之前赋值,避免在循环体内部直接调用。