我们都知道async/await 是生成器函数Generator 的语法糖,那么我们先来探究一下JavaScript中的生成器函数吧。
Generator即生成器函数是ES6提供的一种一部解决方案,Generator是一个内部包含了多种状态的状态机。下面是一个生成器函数:
function* myGenerator () {
yield 'hello'
yield 'world'
return 'ending'
}
const fn = myGenerator()
console.log(fn.next())
console.log(fn.next())
console.log(fn.next())
他的打印结果是这样的:
调用生成器函数的next方法,返回的是一个包含值和状态的遍历器对象,可以看到当对象的done是false时,说明遇到了return语句。
当一个生成器函数如下时
function* sum() {
yield 3 + 4
}
当没有执行到对应的next语句时,yield后面的计算时不会执行的,也就是所谓的惰性执行。
那么generator函数与async函数的关联是什么呢,通过学习我发现其实async/await其实就是generator加上一个自动执行函数。因为generator是无法自动执行的,必须通过next方法手动执行。 所以只要我们将generator外包裹一个自动执行函数,并返回一个promise,就可以模拟async/await的效果,下面我来实现一下:
const { resolve } = require("path");
const getData = function(n, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(n)
}, time);
})
}
function* myGenerator () {
const n1 = yield getData(10,2000);
console.log(n1)
const n2 = yield getData(20,2000);
console.log(n2)
return
}
function autoTick(generatorFunc) {
return function() {
const gen = generatorFunc.apply(this, arguments)
return new Promise((resolve,reject) => {
let res
function step (key, args) {
try{
res = gen[key](args)
} catch(e) {
reject(e)
}
const { value, done } = res
if(done) {
return resolve(value)
} else {
return Promise.resolve(value).then(value => {
step('next', value)
})
}
}
step('next')
}
)
}
}
autoTick(myGenerator)()
可以看到打印结果是如下,并且每个数字的打印间隔都是2000ms:
其中的myGenerator 方法其实就等价于如下写法:
function* myGenerator () {
const n1 = yield getData(10,2000);
console.log(n1)
const n2 = yield getData(20,2000);
console.log(n2)
return
}
等价于>>>>>
async myGenerator() {
const n1 = await getData(10,2000);
console.log(n1)
const n2 = await getData(20,2000);
console.log(n2)
return
}
通过这次探究我加深了对生成器函数,迭代器,async/await的理解,而不仅仅停留在会用的层面。