4.生成器控制流
支持生成器,迭代器的特殊情况,其中控制流可以暂停和恢复,以便支持与“协同例程”结合Promise的异步编程(见下文)。 [注意:通用异步函数通常由可重用的库提供,这里只是为了更好地理解。 在实践中见co或Bluebird的协程。]
传统的编程语言,早有异步编程的解决方案(其实是多任务的解决方案)。其中有一种叫做"协程"(coroutine),意思是多个线程互相协作,完成异步任务。
协程有点像函数,又有点像线程。它的运行流程大致如下。
第一步,协程A开始执行。
第二步,协程A执行到一半,进入暂停,执行权转移到协程B。
第三步,(一段时间后)协程B交还执行权。
第四步,协程A恢复执行。
上面流程的协程A,就是异步任务,因为它分成两段(或多段)执行。
举例来说,读取文件的协程写法如下。
function* asyncJob() {
// ...其他代码
var f = yield readFile(fileA);
// ...其他代码
}
上面代码的函数asyncJob是一个协程,它的奥妙就在其中的yield命令。它表示执行到此处,执行权将交给其他协程。也就是说,yield命令是异步两个阶段的分界线。
协程遇到yield命令就暂停,等到执行权返回,再从暂停的地方继续往后执行。它的最大优点,就是代码的写法非常像同步操作,如果去除yield命令,简直一模一样。
—摘自ECMAScript 6 入门 阮一峰
ECMAScript 6
//通用异步控制流驱动程序
function async (proc, ...params) {
let iterator = proc(...params)
return new Promise((resolve, reject) => {
let loop = (value) => {
let result
try {
result = iterator.next(value)
}
catch (err) {
reject(err)
}
if (result.done)
resovle(result.value)
else if ( typeof result.value === "object" &&
typeof result.value.then === "function")
result.value.then((value) => {
loop()
},(err) => {
reject(err)
})
else
loop(result.value)
}
loop()
})
}
//特定的应用程序异步构建
function makeAsync (text, after) {
return new Promise((resolve, reject) =>{
setTimeout(() => resolve(text),after)
})
}
//特定的应用程序异步过程
async(function* (greeting) {
let foo = yield makeAsync("foo", 300)
let bar = yield makeAsync("bar", 200)
let baz = yield makeAsync("bar", 100)
return `${greeting} ${foo} ${bar} ${baz}`
},"Hello").then((msg) => {
console.log("RESULT:", msg) //"Hello foo bar baz"
})
ECMAScript 5
//ES5中没有响应的表达方式
5.生成器方法
基于生成器函数支持生成器方法,即类和对象中的方法。
ECMAScript 6
class Clz {
* bar () {
...
}
}
let Obj = {
* foo () {
...
}
}
ECMAScript 5
//ES5中没有响应的表达方式