这一切还要从生产环境上客户导入了5000多个部门说起。所以当部门有5000多个的时候,页面出现了明显的卡顿现象。
由于部门是vuex中全局使用的一个数据,所以在首页加载时就会进行加载,而首页数据又需要等待部门处理完后再加载。于是当首页部门数据较多的时候出现了长时间的等待。
通过chrome浏览器调试发现耗时最大的是一个dealTree的方法,什么,我写的代码居然有问题?
找到了相关的代码:
export function getTreeData(list = []) {
console.time('getTreeData')
const firstDep = list.sort((a, b) => a.parentId - b.parentId)[0] || {}
const tree = list.filter(d => d.depId === firstDep.depId || 0)
// 递归设置子级部门
function setChildren(item, list) {
const children = list.filter(i => i.parentId === item.depId)
if (children.length > 0) {
children.map(c => {
setChildren(c, list)
})
item.children = children
}
}
tree.map(item => {
setChildren(item, list)
})
console.timeEnd('getTreeData')
// console.log('------firstDepId', firstDep, list, tree)
return tree
}
数据结构如下:
data = [
{depId: 1, name: "一级", parentId: 0},
{depId: 2, name: "二级", parentId: 1},
{depId: 3, name: "三级", parentId: 2},
...
]
某个客户的数据如下:
这特么是我写的代码?
这特么5000多条数据循环那么多次,不卡才怪!
找到问题了,接下来开始优化,既然是一个平级的树结构,且通过parentId可以区分每个部门的子部门集合,那就用个Set或者Object把所有的部门分好组存储起来,然后通过属性读取相应的子部门即可,通过属性读取的速度比数组的循环是快很多的。
新的方法代码如下:
export function getTreeData2(list = []) {
console.time('getTreeData2')
const childMap = {}
const parentIdSet = new Set()
// 首次遍历将部门根据parentId分好组
for (let i = 0; i < list.length; i++) {
const item = list[i]
parentIdSet.add(item.parentId)
if (childMap[item.parentId]) childMap[item.parentId].push(item)
else childMap[item.parentId] = [item]
}
// 将parentId排序
const topDepId = Array.from(parentIdSet).sort((a, b) => a - b)[0]
const tree = childMap[topDepId] || []
function setDepChildren(dep) {
const children = childMap[dep.depId] || []
if (children.length > 0) {
children.map(c => {
setDepChildren(c)
})
dep.children = children
}
}
tree.map(item => {
setDepChildren(item)
})
console.timeEnd('getTreeData2')
return tree
}
再让我们看一下这两个方法处理数据的对比,以下是点击执行20次的效果对比点这里看对比
不错,改完之后,首页加载终于顺畅了很多
总结: 写代码的时候一直很少注重性能,更多关注业务实现,有时候业务功能是实现了,没想到给后面埋了坑。不过吃一堑,长一智。记录下来,与小伙伴门共勉。