要让普通对象支持 for await...of,必须实现 symbol.asynciterator 方法并返回异步迭代器(next() 返回 promise);proxy 仅用于无侵入拦截注入该能力,不能绕过协议本质。

要让普通对象支持 for await...of,关键不是给它加个 Proxy 就行,而是必须让它满足异步迭代协议——即拥有 [Symbol.asyncIterator]() 方法,且该方法返回一个**异步迭代器对象**(其 next() 返回 Promise)。Proxy 在这里的作用是「动态拦截并注入」这个能力,尤其适合对已有对象做无侵入包装。
核心思路:用 Proxy 拦截 Symbol.asyncIterator 访问
普通对象默认没有 [Symbol.asyncIterator],直接访问会返回 undefined。我们可以用 Proxy 拦截 get 操作,当检测到访问的是 Symbol.asyncIterator 时,动态返回一个符合协议的异步迭代器函数。
- 不修改原对象,保持干净
- 可复用同一套包装逻辑处理不同数据源(如数组、Map、自定义配置)
- 便于统一控制节奏(如添加延迟、限流、错误重试)
基础包装:把数组转成异步可迭代对象
假设你有一个普通数组 [1, 2, 3],想让它能被 for await...of 逐项等待(比如模拟网络延迟):
用于 inference.sh 的 JavaScript/TypeScript SDK,可运行 AI 应用、构建代理、集成 150+ 模型。包名:@inferencesh/sdk(npm install),完整 TypeScript 支持。
function asyncIterableFrom(arr) {
return new Proxy(arr, {
get(target, prop, receiver) {
if (prop === Symbol.asyncIterator) {
return function() {
let i = 0;
return {
next() {
if (i {
setTimeout(() => {
resolve({ value: target[i++], done: false });
}, 100);
});
}
return Promise.resolve({ value: undefined, done: true });
}
};
};
}
return Reflect.get(target, prop, receiver);
}
});
}
// 使用
const asyncArr = asyncIterableFrom([10, 20, 30]);
(async () => {
for await (const n of asyncArr) {
console.log(n); // 10 → 20 → 30,每项间隔 100ms
}
})();
增强版:支持异步数据源与错误传播
如果原始对象的数据本身来自异步调用(如 API 分页),可在 next() 中执行 await。Proxy 包装层可封装加载逻辑,并确保错误被正确抛出:
-
next()内部可await fetch或调用任意异步函数 - 异常会自然冒泡到
for await...of外层,可用try/catch捕获 - 可通过闭包或 WeakMap 关联状态(如当前页码、token),避免污染原对象
注意边界:不能绕过协议本质
Proxy 只是代理访问,无法让一个“非异步可迭代对象”凭空变成合法的异步可迭代对象。以下情况仍会失败:
- 原对象没提供数据源(比如空对象
{}),又没在next()中约定如何生成值 - 返回的
next()不返回 Promise,或 Promise resolve 的结构缺value或done - 在非
async函数中使用for await...of,会直接报语法错误










