Vue应用中循环内调用的reduce函数运行过慢导致页面冻结如何优化
性能优化方案
1. 优先解决 O(n*m) 级别的最大性能瓶颈
你当前代码中耗时最长的点是 reduce 内部每次遍历行数据时,都调用 Array.find 在 kitsData 中匹配对应数据。如果有12000条行数据、同时 kitsData 也有上千条的话,这部分的时间开销会占到总耗时的90%以上。
优化方式:提前把 kitsData 转换为以 heir_identifier 为key的对象映射表,查找时间直接降到 O(1)。
// 拿到kitsData后立即预处理为映射表,全程只需要执行一次 this.kitsMap = this.kitsData.reduce((map, kit) => { map[kit.heir_identifier] = kit return map }, {})
替换reduce内的查找逻辑:
// 原写法,每次都遍历整个kitsData // const foundKit = vm.$data.kitsData.find((kit) => kit.heir_identifier === sku.heir_id) // 优化后写法,直接从映射表取 const foundKit = this.kitsMap[sku.heir_id]
仅这一项修改,reduce的执行速度至少可以提升90%。
2. 精简reduce内部的冗余操作
- 提前把字符串类型的数值转为数字,避免每次运算都做隐式转换
- 员工的公共属性(area、group、warehouse等)仅在首次创建对象时赋值,不需要每次遍历行数据都重复覆盖
- 删掉无用的全局
status变量赋值,你的代码中status是全局变量,不仅会导致数据错乱,还增加了不必要的操作
优化后的reduce核心逻辑:
const reduceFunction = (rows, kitsMap) => rows.reduce((a, row) => { // 提前统一转数值 const catePerItem = Number(row.categories_per_item) const qty = Number(row.qty) // 首次创建员工对象时就赋值固定属性,避免重复赋值 const employee = a[row.employee] || (a[row.employee] = { dates: {}, total_categories:0, total_items: 0, area: row.area, group: row.group_name, warehouse: row.warehouse, locale: row.locale }) const date = employee.dates[row.itemDate] || (employee.dates[row.itemDate] = { categories: 0, qty: 0, total_categories: 0, unavailable: 0, orders: {} }) date.categories += catePerItem * qty date.qty += qty date.total_categories = date.categories const order = date.orders[row.order_number] || (date.orders[row.order_number] = {itemDate: row.itemDate, skus: {}}) const sku = order.skus[row.sku] || (order.skus[row.sku] = { categories: 0, qty: 0, itemDate: row.itemDate, expected: row.shipDate, created: row.created_date, unavailable: 0, available:0, heir_id: row.heir_identifier }) sku.categories += catePerItem sku.qty += qty employee.total_categories += catePerItem * qty employee.total_items += qty const foundKit = kitsMap[sku.heir_id] if (foundKit) { const new_avail = 10 if(sku.qty > new_avail){ date.unavailable += 1 sku.unavailable += 1 } } return a }, {})
计算属性调用方式修改为传入映射表:
employeeData() { return reduceFunction(this.rows, this.kitsMap) }
3. 优化模板渲染逻辑,删除嵌套循环判断
你当前的模板中,每个日期单元格都要遍历该员工的所有日期数据,再用v-if判断是否匹配当前日期,12000条员工数据+11天日期的场景下,会多出十几万次无效循环。
优化方式:直接通过日期key取对应值,完全删掉嵌套的v-for和v-if:
<div id="app"> <tr v-for="(value, employee) in employeeData" :key="employee"> <td>@{{employee}}</td> <td v-for="date in dates" :key="date" > @{{ value.dates[date]?.total_categories || '' }} </td> </tr> </div>
修改后渲染速度可以提升数倍。
4. 超大数据量的额外优化
如果做完上述优化后渲染仍然卡顿,可以引入虚拟滚动组件,仅渲染可视区域内的DOM,不管多少条数据都不会出现卡顿。如果不需要一次性展示所有数据,也可以做分页处理,每页仅渲染几十条数据即可。
内容的提问来源于stack exchange,提问作者Geoff_S
相关产品推荐
相关产品推荐

