一次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对象的访问开销太大,最好在使用之前赋值,避免在循环体内部直接调用。