要让自定义对象支持 for-await-of 遍历,关键在于实现 [Symbol.asyncIterator]() 方法,它必须返回一个具有 next() 方法的异步迭代器对象,next() 返回 Promise,done 为 true 表示结束。

要让自定义对象支持 for-await-of 遍历,关键在于实现 [Symbol.asyncIterator]() 方法,它必须返回一个符合异步迭代器协议的对象(即具有 next() 方法、返回 Promise 并最终 resolve { value, done })。
理解异步迭代器协议
Symbol.asyncIterator 是一个内置 symbol,用于标识对象的异步迭代器。当 JavaScript 引擎遇到 for-await-of 时,会自动调用该 symbol 方法获取迭代器,并反复调用其 next() 方法,等待每个 Promise 解析。
-
next()必须返回Promise -
done: true表示遍历结束,之后的next()调用也应返回{ value: undefined, done: true } - 迭代器本身不要求是 async function,但
next()的返回值必须是 Promise
手动实现一个可暂停的异步计数器
下面是一个每次 next() 延迟 1 秒后返回递增数字的异步迭代器:
class DelayedCounter {
constructor(max = 5) {
this.max = max;
this.current = 0;
}
[Symbol.asyncIterator]() {
return {
i: 0,
max: this.max,
next() {
if (this.i < this.max) {
const value = this.i++;
return Promise.resolve({ value, done: false });
}
return Promise.resolve({ value: undefined, done: true });
}
};
}
}
// 使用
(async () => {
for await (const num of new DelayedCounter(3)) {
console.log(num); // 0, 1, 2(每秒输出一个)
}
})();
结合真实异步源(如 fetch 流或事件)
实际中常需包装 ReadableStream、EventTarget 或定时任务。例如,将一个字符串数组逐项异步读取:
function asyncArrayIterator(arr) {
let i = 0;
return {
next() {
if (i < arr.length) {
// 模拟异步 IO,比如 await fetch()
return Promise.resolve({ value: arr[i++], done: false });
}
return Promise.resolve({ value: undefined, done: true });
}
};
}
const data = ['a', 'b', 'c'];
const iterable = {
[Symbol.asyncIterator]: () => asyncArrayIterator(data)
};
(async () => {
for await (const item of iterable) {
console.log(item); // a → b → c
}
})();
注意错误处理与取消逻辑
异步迭代器本身不强制支持取消,但可在 next() 中响应外部信号(如 AbortSignal):
- 在
next()内部检查signal.aborted,提前 reject - 若需清理资源(如关闭连接),建议额外提供
return()或throw()方法(非必需,但符合完整协议) -
for-await-of遇到异常会自动退出,且不会再次调用next()
不复杂但容易忽略:确保每次 next() 返回的是新 Promise,避免状态复用导致行为异常。

















