登录
首页 >  文章 >  前端

JavaScript中yield在异步迭代中的暂停作用

时间:2026-04-06 12:06:13 496浏览 收藏

JavaScript 中的 `yield` 本身并不具备异步能力,它仅负责暂停生成器执行并交出控制权;真正的异步暂停依赖于 `yield` 后接 Promise 并由调用方通过 `await`、`for-await-of` 或手动 `next()` 调度来实现等待——而 `async function*` 异步生成器则让 `yield` 可以原生等待 Promise 完成后再产出值,从而在保持生成器语义的同时,提供简洁、可控且符合直觉的异步迭代体验,既适合逐项延迟处理,也支持并发预加载等高级场景。

JavaScript中yield关键字在异步迭代中的状态暂停

yield 本身不处理异步,它只是暂停生成器函数的执行,并交出控制权;真正实现“异步迭代中状态暂停”的,是 yield 后接 Promise + 配合 await 或 next() 的手动调度

yield 不会自动等待异步操作完成

在生成器函数中写 yield fetch('/api/data'),并不会等请求返回再继续。它只是把创建好的 Promise 对象立刻 yield 出去,然后暂停。后续是否等待、如何等待,由调用方(比如 for-await-of 或手动调用 next())决定。

  • 直接调用 gen.next() 返回的是 { value: Promise, done: false },Promise 还处于 pending 状态
  • 若想等请求完成,需在外部 await value,或用 async function* (异步生成器)配合 await yield

异步生成器(async function*)让 yield 真正“等”异步结果

使用 async function* 声明生成器后,内部可用 await yield,此时 yield 表达式会等待右侧 Promise settle 后再产出值:

async function* asyncCounter() {
  for (let i = 1; i  setTimeout(r, 1000)); // 模拟异步延迟
    yield i; // 这里的 yield 会等上面的 await 完成后再执行
  }
}

这时用 for await (const val of asyncCounter()) 就能按秒依次拿到 1、2、3 —— 暂停点由 await 控制,yield 负责产出。

手动调度 next() 时,暂停状态由你掌控

生成器对象的 next() 方法本身是同步的,但你可以选择何时调用它、是否 await 其 value:

  • 同步调用 it.next() → 得到 {value: Promise, done: false},不暂停异步过程
  • 写成 const res = await it.next(); await res.value; → 显式等待异步结果,实现可控暂停
  • 搭配 Promise.all([...]) 可并发拉取多个异步项,再统一 yield,适合批量预加载场景

for-await-of 是最自然的消费方式

只要生成器是 async function*,且每个 yield 后都经过 await(或 yield 的是已 resolve 的 Promise),for await 就会自动等待每次 yield 完成后再进入下一轮循环:

async function* fetchUsers() {
  const ids = [1, 2, 3];
  for (const id of ids) {
    const user = await fetch(`/user/${id}`).then(r => r.json());
    yield user; // 每次 yield 前都等到了 user 数据
  }
}
<p>// 使用时:
for await (const user of fetchUsers()) {
console.log(user); // 依次打印,每条间隔由 fetch 决定
}</p>

这种写法隐藏了手动调用 next 和 await 的细节,让异步迭代看起来像同步遍历,但底层仍是基于 yield 的暂停/恢复机制。

好了,本文到此结束,带大家了解了《JavaScript中yield在异步迭代中的暂停作用》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多文章知识!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>