async generator 和 for await...of 只能在 async 函数或 type="module" 脚本中使用,需返回符合 Symbol.asyncIterator 协议的对象,且错误须在 for await 外层 try/catch 捕获。

不能直接在 HTML 中使用 async generator 或 for await...of —— 它们是 JavaScript 运行时特性,不是 HTML 标签或属性。你真正要做的,是在 <script> 块里用 JS 写异步生成器逻辑,并用 for await...of 消费它。
async function* 必须定义在顶层 async 函数或模块作用域中
浏览器不支持在普通脚本(非 type="module")中直接执行 for await...of,会报 SyntaxError: for await...of is not supported in this context。原因:该语法只能在 async 函数内部或 ES 模块顶层(需显式启用)中使用。
- ✅ 正确写法:包裹在立即执行的 async 函数里
- ✅ 正确写法:把
<script type="module">作为脚本类型(现代浏览器支持) - ❌ 错误写法:在普通
<script>里直接写for await...of循环
async generator 返回的是异步可迭代对象,必须实现 Symbol.asyncIterator
只有返回的对象满足异步迭代协议(即有 [Symbol.asyncIterator]() 方法,且该方法返回一个 next() 返回 Promise 的对象),才能被 for await...of 消费。普通 Promise 数组、fetch() 调用结果、甚至 Array.from() 包装都不行。
- ✅
async function*自动满足该协议 - ❌
Promise.all([p1, p2, p3])是单个 Promise,不是可迭代对象 - ❌
[fetch('/a'), fetch('/b')]是同步数组,元素是 Promise,但数组本身不实现Symbol.asyncIterator - ⚠️ 若想包装普通 Promise 数组,得手动实现
Symbol.asyncIterator,否则会报TypeError: xxx is not async iterable
常见错误:在 forEach / map 里滥用 await
很多人想“并发拉多页数据再逐个处理”,却误写成:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
立即学习“前端免费学习笔记(深入)”;
urls.forEach(async url => {
const res = await fetch(url);
const data = await res.json();
console.log(data);
});
这不会按顺序等待,也不会阻塞循环;三个请求几乎同时发出,输出顺序不可控。而 for await...of 配合 async function* 才能真正实现「串行等待 + 流式吐出」。
- ✅ 想串行:用
for await (const item of asyncGenerator()) - ✅ 想并发控制(如最多 3 个并行):需额外加信号量逻辑,
async function*本身不提供并发限制 - ⚠️ 注意:每个
yield后的值,会被for await自动await;所以yield fetch(...)和yield (await fetch(...)).json()效果不同 —— 前者 yield 的是 Promise,后者是解析后的值
真实分页场景下的最小可行示例
比如从 /api/logs?page=1 到 page=3 分批拉日志,每页等 500ms 再发下一页(模拟节流):
async function* fetchLogs() {
for (let page = 1; page <= 3; page++) {
const res = await fetch(`/api/logs?page=${page}`);
const logs = await res.json();
yield logs; // ← 这行之后,for await 会暂停,直到本轮处理完
await new Promise(r => setTimeout(r, 500)); // 可选节流
}
}
<p>// 必须在 async 函数内调用
(async () => {
try {
for await (const logs of fetchLogs()) {
console.log(<code>Received ${logs.length} logs</code>);
// 这里可以做渲染、存 localStorage、append 到 DOM 等
document.getElementById('log-list').insertAdjacentHTML('beforeend',
logs.map(l => <code><div>${l.message}</div></code>).join('')
);
}
} catch (err) {
console.error('Fetch failed:', err);
}
})();
关键点在于:yield 的不是原始响应,而是已解析的数据;错误必须在 for await 外层用 try/catch 捕获 —— for await 本身不捕获异步生成器内部抛出的异常。


















