在 JavaScript 中,协程(即协作多任务)可以通过生成器(Generator)和 yield 关键字实现。要了解协程的底层原理,我们需要了解生成器、迭代器和 JavaScript 事件循环的概念。
- 生成器(Generator) :生成器是 JavaScript 中一种特殊的函数(使用
function*声明),它可以在执行过程中产生多个值,并通过特殊的控制命令(称为生成器对象)在需要时返回。与普通函数不同,生成器函数执行并不会一直运行到完成,而是可以在中间暂停和恢复。生成器内部使用yield关键字暂停执行并将控制权交还给生成器对象。生成器对象可以将控制权返还给生成器函数,用于从上次暂停的地方继续执行。 - 迭代器(Iterator) :生成器函数执行后,会返回一个生成器对象。这个生成器对象遵从迭代器协议和生成器协议,可以通过调用
next()方法来按需恢复生成器函数的执行。next()方法返回一个对象,包含生成器产生的值(value)和一个标志(done),用于表示生成器是否已达到最后状态。 - 事件循环(Event Loop) :JavaScript 通过单线程的事件循环来实现异步处理。事件循环会不断检查任务队列(message queue)、微任务队列(microtasks queue)等,有任务就执行。事件循环使得 JavaScript 可以处理多个异步操作,无论何时异步操作完成,都可以将相应的回调函数添加到任务队列中。
结合以上三个概念,可以理解 JavaScript 中协程的底层原理:
- 使用生成器函数定义协程,生成器函数包含需要异步处理的任务。
- 生成器函数执行后,会返回一个生成器对象,它遵从迭代器协议。
- 通过调度器(即协程的高层调用者)来控制生成器对象的运行顺序。调度器可以是一段自定义的代码(如通过
function.next()方法调用生成器对象)或第三方库。 - 当一个异步操作完成时,将回调函数或 Promise 处理程序添加到任务队列中。事件循环会执行这个回调函数,恢复协程执行。
- 如果协程中还有其他异步操作需要等待,那么继续重复以上步骤,直到协程结束。
通过这种方式,协程可以让我们在同步风格的代码中处理异步操作,并在执行期间将控制权传递给其他协程或处理程序。在生成器和事件循环之间进行切换,让 JavaScript 能高效地处理并发任务和复杂的控制流。