
本文介绍如何通过一次遍历替代多次 filter() 调用,高效构建含分类计数与子集对象的数组结构,显著提升性能并增强代码可维护性。
本文介绍如何通过一次遍历替代多次 `filter()` 调用,高效构建含分类计数与子集对象的数组结构,显著提升性能并增强代码可维护性。
在处理大型请求数据(如 details.request)时,频繁调用 Array.prototype.filter() 会导致严重的性能损耗——每次调用都需完整遍历整个数组。原代码中为计算“In-Progress”“Success”“Failed”三类的 count 和 additionalObj,共执行了 6 次独立遍历(每个类别 2 次),时间复杂度达 O(6n),且存在重复逻辑和冗余判断。
更优解是采用 单次遍历 + 分类累加 策略:使用 forEach 或 for...of 遍历一次原始数组,根据 statusId 值同步更新对应计数器与结果数组。该方法将时间复杂度降至 O(n),内存访问局部性更好,且逻辑清晰、易于扩展。
以下是优化后的专业实现:
function partitionRequests(details: { request: { statusId: number }[] }) {
let inProgressCount = 0;
let successCount = 0;
let failedCount = 0;
const successAdditionalObj: typeof details.request = [];
const failedAdditionalObj: typeof details.request = [];
for (const req of details.request) {
switch (req.statusId) {
case 0:
case 1:
case 3:
case 4:
inProgressCount++;
break;
case 6:
successCount++;
successAdditionalObj.push(req);
break;
case 2:
case 5:
failedCount++;
failedAdditionalObj.push(req);
break;
// 忽略其他 statusId(如 undefined、7+),无需 default 分支也可保持静默
}
}
return [
{
label: 'Total',
count: details.request.length,
},
{
label: 'In-Progress',
count: inProgressCount,
},
{
label: 'Success',
count: successCount,
additionalObj: successAdditionalObj,
},
{
label: 'Failed',
count: failedCount,
additionalObj: failedAdditionalObj,
},
];
}
// 使用方式(TypeScript/JS 均适用)
this.data = partitionRequests(details);✅ 关键优化点说明:
立即学习“Java免费学习笔记(深入)”;
- ✅ 零重复遍历:仅一次 for...of 完成全部分类与收集;
- ✅ 类型安全(TS 友好):复用 typeof details.request 推导子数组类型;
- ✅ 语义清晰:switch 比链式 || 判断更易读、更易维护,也利于 V8 引擎优化;
- ✅ 内存友好:避免 filter() 创建中间数组,减少 GC 压力;
- ✅ 可扩展性强:新增状态分类只需在 switch 中添加 case,无需新增遍历逻辑。
⚠️ 注意事项:
- 若 details.request 可能为 undefined 或 null,建议在函数开头添加守卫:if (!Array.isArray(details?.request)) return [];;
- 如需兼容 IE,将 for...of 替换为传统 for (let i = 0; i < arr.length; i++);
- 若后续需支持动态配置状态映射(如从外部传入规则),可进一步封装为高阶函数,但当前场景下硬编码 switch 更高效、更直观。
综上,单次遍历不仅是性能优化的最佳实践,更是面向数据聚合场景的工程范式升级——用确定性的控制流替代冗余的函数式调用,让代码既快又稳。


















