传统的编程语言,早有异步编程的解决方案(其实是多任务的解决方案)。其中有一种叫做“协程”(coroutine),意思是多个线程互相协作,完成异步任务。
协程有点像函数,又有点像线程,它的运行流程大致如下:
- 第一步,协程
A
开始执行; - 第二步,协程
A
执行到一半,进入暂停,执行权转移到协程B
; - 第三步,(一段时间后)协程
B
交还执行权; - 第四步,协程
A
恢复执行;
上面流程的协程 A
,就是异步任务,因为它分成两段(或多段)执行。
举例来说,读取文件的协程写法如下:
function* asyncJob() {
// ...
var f = yield readFile(fileA);
// ...
}
上面代码的函数 asyncJob
是一个协程,它的奥妙就在其中的 yield
命令。它表示执行到此处,执行权将交给其他协程。也就是说,yield
命令是异步两个阶段的分界线。协程遇到 yield
命令就暂停,等到执行权返回,再从暂停的地方继续往后执行。
Generator
函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。
function* gen(x) {
var y = yield x + 2;
return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: false }
next
是返回值的 value
属性,是 Generator
函数向外输出数据;next
方法还可以接受参数,向 Generator
函数体内输入数据。
上面代码中,第一个 next
方法的 value
属性,返回表达式 x + 2
的值 3
。第二个 next
方法带有参数 2
,这个参数可以传入 Generator
函数,作为 上个阶段
异步任务的返回结果,被函数体内的变量 y
接收。因此,这一步的 value
属性,返回的就是 2
(变量 y
的值)。