1. 基础循环(最高性能)
// 传统for循环(推荐缓存长度)
for (let i = 0, len = arr.length; i < len; i++) {
// 操作 arr[i]
}
// while循环(条件驱动)
let i = 0;
while (i < arr.length) {
// 操作 arr[i]
i++;
}
// do...while循环(保证至少执行一次)
let j = 0;
do {
// 操作 arr[j]
j++;
} while (j < arr.length);
性能特点:
- ⭐⭐⭐⭐⭐ (最快)
- 直接内存访问,无额外开销
- 引擎优化程度最高
- 支持break/continue控制
2. 数组迭代方法
// forEach(简洁但不可中断)
arr.forEach(item => {
// 操作 item
});
// map(创建新数组)
const newArr = arr.map(item => transform(item));
性能特点:
- ⭐⭐ (中等)
- 比基础循环慢60-70%
- 每次迭代产生函数调用开销
- 无法中断循环
3. 对象/迭代器循环
// for...in(对象属性遍历)
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
// 操作 obj[key]
}
}
// for...of(可迭代对象遍历)
for (const item of arr) {
// 操作 item
}
性能特点:
- for…in: ⭐ (最差)
- for…of: ⭐⭐⭐ (良好)
- for…in 比基础循环慢95%以上
- for…of 接近基础循环性能
4. 异步循环
// for await...of(异步迭代)
for await (const item of asyncIterable) {
await process(item);
}
特点:
- 专为异步操作设计
- 顺序处理异步任务
- 性能取决于异步操作本身
性能对比数据(100万元素数组)
循环类型 | Chrome 时间 | Firefox 时间 | 相对性能 | 内存开销 |
---|---|---|---|---|
for (缓存长度) | 4.2ms | 4.8ms | 100% | 最低 |
while | 4.5ms | 5.1ms | 95% | 最低 |
do…while | 4.5ms | 5.2ms | 95% | 最低 |
for…of | 5.8ms | 6.5ms | 80% | 低 |
forEach | 12.1ms | 14.3ms | 38% | 高 |
for…in (数组) | 1100ms | 980ms | 0.4% | 最高 |
测试环境:Intel i7-12700H, 32GB RAM, Win11
中断能力对比
方法 | break | continue | return | 适用场景 |
---|---|---|---|---|
for | ✅ | ✅ | ✅ | 通用循环 |
while | ✅ | ✅ | ✅ | 条件复杂循环 |
do…while | ✅ | ✅ | ✅ | 至少执行一次的场景 |
for…of | ✅ | ✅ | ✅ | 可迭代对象 |
for…in | ✅ | ✅ | ✅ | 对象属性遍历 |
forEach | ❌ | ❌ | ❌ | 简单数组遍历 |
for await…of | ✅ | ✅ | ✅ | 异步迭代 |
最佳实践指南
- 数组遍历选择
// 高性能场景(推荐)
for (let i = 0, len = data.length; i < len; i++) {
if (data[i] === null) break;
process(data[i]);
}
// 可读性优先(无中断需求)
data.forEach(item => {
display(item);
});
// 需要中断的现代语法
for (const item of data) {
if (shouldSkip(item)) continue;
if (shouldStop(item)) break;
transform(item);
}
- 对象遍历选择
// 安全遍历对象属性
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(`${key}: ${obj[key]}`);
}
}
// 现代替代方案
Object.keys(obj).forEach(key => {
console.log(`${key}: ${obj[key]}`);
});
- 优化技巧
// 1. 缓存数组长度
for (let i = 0, len = largeArray.length; i < len; i++)
// 2. 倒序循环(减少条件判断)
for (let i = arr.length - 1; i >= 0; i--)
// 3. 减少循环内操作
// 坏实践
for (let i = 0; i < 1000; i++) {
const value = calculate(); // 每次循环都计算
}
// 好实践
const value = calculate(); // 预先计算
for (let i = 0; i < 1000; i++) {
// 使用预先计算的值
}
- 避免性能陷阱
// 陷阱1:for...in遍历数组
// 错误(极慢且可能出错)
for (const index in array) {
console.log(array[index]);
}
// 正确
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
// 陷阱2:在forEach中模拟中断
// 错误(不推荐)
try {
arr.forEach(item => {
if (condition) throw new Error('Break');
});
} catch (e) {}
// 正确
for (const item of arr) {
if (condition) break;
}
循环选择决策树
特殊场景处理
- 稀疏数组处理
// 跳过空元素
for (let i = 0; i < sparseArray.length; i++) {
if (!(i in sparseArray)) continue;
process(sparseArray[i]);
}
- 循环中的异步操作
// 顺序执行异步操作
async function processArray(array) {
for (const item of array) {
await asyncOperation(item);
}
}
// 并行执行异步操作
async function processParallel(array) {
await Promise.all(array.map(item => asyncOperation(item)));
}
- 循环性能测试代码
function testLoopPerformance(arr, loopType) {
const start = performance.now();
switch(loopType) {
case 'for':
for (let i = 0; i < arr.length; i++) void arr[i];
break;
case 'for-cached':
for (let i = 0, len = arr.length; i < len; i++) void arr[i];
break;
case 'for-of':
for (const item of arr) void item;
break;
case 'forEach':
arr.forEach(item => void item);
break;
}
const duration = performance.now() - start;
return duration;
}
总结建议
- 首选基础循环:性能关键代码使用for或while
- 数组遍历:
- 简单遍历:forEach
- 需要中断:for…of
- 最高性能:for(缓存长度)
- 对象遍历:for…in + hasOwnProperty
- 避免:
- for…in遍历数组
- 在循环内创建函数
- 不必要的计算重复
- 现代语法:for…of平衡性能和可读性
通过理解不同循环的性能特点和适用场景,您可以在开发中做出更明智的选择,编写出既高效又易维护的JavaScript代码。