JavaScript 的协程概念是如何通过 Generator 和 Async/Await 实现的?

JavaScript 的协程概念是如何通过 Generator 和 Async/Await 实现的?
最新回答
待春暖花開

2026-10-31 15:28:59

JavaScript 本身是单线程语言,不支持传统多线程协程,但通过 Generator 函数和 Async/Await 实现了类似协程的“可暂停与恢复执行”能力,从而支持异步流程的有序控制。以下是具体实现方式及核心机制:

1. Generator:手动控制的协程

Generator 是 ES6 引入的特殊函数,通过 function* 定义,使用 yield 暂停执行,外部通过迭代器对象控制恢复,实现协程的核心特征。

  • 执行中断与上下文保留遇到 yield 时,函数暂停执行,保留当前变量状态(如局部变量、循环位置等),下次恢复时从暂停处继续。

  • 外部控制与双向通信

    返回迭代器对象,通过 .next() 手动恢复执行。

    .next(value) 可向函数体内传值(作为 yield 表达式的返回值)。

    yield 表达式可向外返回值(通过 .next().value 获取)。

  • 示例

    function* counter() { let count = 0; while (true) { yield ++count; // 暂停并返回值 }}const gen = counter();console.log(gen.next().value); // 1(恢复执行,count=1)console.log(gen.next().value); // 2(恢复执行,count=2)

    每次调用 .next() 恢复执行,直到下一个 yield 或函数结束。

    类似“可随时暂停和恢复的任务”,具备协程的协作式调度特性。

  • 早期应用Generator 最初用于解决回调地狱,配合工具库(如 co)实现自动执行异步流程,但需手动驱动或依赖外部库。

2. Async/Await:基于 Promise 的自动协程

Async/Await 是 Generator 的语法升级,底层依赖 Promise,但以同步语法自动处理异步流程,无需手动驱动。

  • 自动执行机制

    async 函数自动返回 Promise,内部使用 await 暂停执行,直到 Promise 完成(resolve/reject)。

    无需手动调用 .next(),引擎自动处理暂停与恢复。

  • 错误处理与语义清晰

    使用 try/catch 捕获异步错误,结构接近同步代码。

    示例:async function fetchData() { try { const res = await fetch('/api/data'); // 暂停,等待响应 const data = await res.json(); // 暂停,等待解析 return data; } catch (err) { console.error(err); // 捕获异步错误 }}fetchData().then(data => console.log(data));

    代码逻辑线性展开,避免回调嵌套或 Generator 的手动控制。

  • 与 Generator 的关系Async/Await 可视为 Generator + Promise + 自动执行器 的语法糖。例如,以下 Generator 代码需手动驱动:

    function* asyncTask() { const res = yield fetch('/api/data'); // 暂停,需外部处理 const data = yield res.json(); return data;}// 需配合 co 库或手动调用 .next()

    而 Async/Await 直接内置流程控制,成为现代异步编程标准。

3. 两者关系与演进
  • Generator 的原始模型提供协程的基础能力(暂停/恢复、双向通信),但需手动控制或依赖工具库,适合底层实现。

  • Async/Await 的升级

    自动化执行流程,简化异步代码。

    结合 Promise 的状态管理(pending/fulfilled/rejected),提供更可靠的错误处理。

    成为 ES2017 后的主流异步编程方式。

总结
  • Generator:通过 yield 和迭代器实现手动控制的协程,适合需要精细调度或双向通信的场景。
  • Async/Await:基于 Promise 的自动协程,以同步语法简化异步逻辑,是现代 JavaScript 的标准实践。两者共同解决了单线程语言下的异步控制问题,使代码更清晰、易维护。