JS如何实现协程控制

JS如何实现协程控制
最新回答
考考死

2021-09-04 17:54:34

JavaScript中可通过生成器和async/await模拟协程控制,二者分链做培别基于不同机制实现协作式暂停与恢复,适用于不同场景且可结合使用。

生成器(Generators)实现协作式暂停与恢复
  • 定义与声明:生成胡雀器函数通过function*声明,如function* myGenerator() { ... }。它返回一个生成器对象,该对象是迭代器,可通过next()方法驱动执行。
  • 暂停与恢复机制

    暂停:在生成器函数内部使用yield关键字,执行到yield时函数暂停,保存执行上下文(局部变量、执行位置等),并将yield后表达式的值返回给调用者。例如:

function* taskRunner() { console.log('任务A:开始'); yield '等待外部指令1'; console.log('任务B:进行中'); yield '等待外部指令2'; console.log('任务C:完成'); return '所有任务完成'; }
  • 恢复:调用生成器对象的next()方法,函数从上次yield的地方继续执行,直到遇到下一个yield或函数结束。next()方法返回一个对象,包含value(yield表达式的值)和done(表示生成器是否已完成)两个属性。如上述例子中,每次调用runner.next()都会恢复生成器执行并返回相应结果。
  • 双向通信:通过next()方法可向生成器内部传递参数,实现双向通信。例如:
function* generatorWithInput() { const input1 = yield '请输入第一个值'; console.log('接收到的第一个值:', input1); const input2 = yield '请输入第二个值'; console.log('接收到的第二个值:', input2); return '输入完成';}const gen = generatorWithInput();console.log(gen.next()); // { value: '请输入第一个值', done: false }console.log(gen.next(10)); // { value: '请输入第二个值', done: false },传递参数10给生成器console.log(gen.next(20)); // { value: '输入完成', done: true },传递参数20给生成器
  • 应用场景

    自定义迭代器或无限序列:可惰性地生成值,避免一次性计算所有结果,如斐波那契数列生成器。

    构建复杂的异步流程控制框架:如Redux Saga利用生成器的yield暂停和控制副作用,以同步方式编写复杂异步逻辑,提供比async/await更细粒度的控制能力,可yield出任何东西。

    模拟协作式多任务处理(非阻塞的同步计算):对于需执行大量计算的函数,为不阻塞UI,可用生成器每次计算一小步后yield,让事件循环处理其他任务,下次next()调用时继续计算。

    构建状态机:每个yield点可看作状态转换点,外部通过next()驱动状态迁移。

async/await实现协程控制
  • 定义与原理:async/await是ES2017引入的基于Promise的语法糖。async函数棚唯内部使用await关键字,它会等待一个Promise的解决。若Promise未解决,async函数暂停执行,将控制权交还给事件循环;Promise解决后,async函数作为微任务重新排队,从await处继续执行。例如:
function simulateAsyncOperation(ms) { return new Promise(resolve => setTimeout(resolve, ms));}async function fetchData() { console.log('开始获取数据...'); await simulateAsyncOperation(1000); console.log('数据A获取完成。'); await simulateAsyncOperation(500); console.log('数据B获取完成。'); return '所有数据已就绪';}fetchData().then(result => { console.log(result);});console.log('主线程继续执行,不会被阻塞。');
  • 与生成器的区别

    底层机制:生成器是更底层、显式、可编程的暂停/恢复原语;async/await是针对异步编程场景的高级抽象,其“暂停”与Promise和事件循环深度绑定。

    驱动方式:生成器需手动调用next()方法驱动;async/await的暂停和恢复是隐式的,由Promise解决机制自动触发后续执行。

  • 应用场景

    处理绝大多数异步操作:如网络请求、文件读写、定时器等基于Promise或回调的异步操作。

    代码可读性和维护性优先:让异步代码看起来像同步代码,简化错误处理(使用try...catch),便于推理异步流程。

    与现有Promise生态系统集成:现代JavaScript的异步API几乎都返回Promise,async/await与它们无缝衔接。

生成器与async/await的选择及结合使用
  • 选择依据:根据具体需求和问题选择。处理常规异步操作、追求可读性和维护性、与Promise生态集成时选async/await;实现自定义迭代、协作式多任务、状态机或需细粒度控制的异步框架时选生成器。
  • 结合使用:二者可结合,如一些高级异步库中,生成器可驱动async/await流程,实现更强大的控制流管理。