阅读本文前, 你需要准备前置知识: ES6生成器 - generator
async await 是ES7的异步解决方案,让我们的异步处理函数能使用同步代码的方式编写,其实内部是巧妙的结合了ES6中的Promise和生成器。
一、生成器函数
- 生成器函数就是普通函结构加上
*和yield
生成器函数以下写法都是正确的,看例子:
// 靠着函数名
function *generator(){
yiled 'cellphone'
}
// 靠着函数声明
function* generator(){
yield 'cellphone'
}
// 两边都不靠
function * generator(){
yield 'cellphone'
}
- 生成器函数使用
// 声明两个Promise模拟异步
const getData = Promise.resolve(1)
const login = Promise.resolve(2)
// 实现的效果如果可以像下面代码这么写,
// 就相当于实现了async await
function *fn() {
const a = yield getData;
console.log(a); // 1
const b = yield login;
console.log(b); // 2
}
// 关键是 怎么处理生成器函数,
// 才能得到上面代码的结果呢,往下看
// 1.fn像普通函数那样执行,但并不会真正执行,
//仅仅是得到迭代器gen,gen.next()才能控制函数的执行
const gen = fn();
/*第一次调用next的时候,函数开始执行 遇到第一个yeild,
函数停在会执行到yield处,并且返回yield的结果,
yiled的结果一个对象 {value:getData, done: false}
value就是yield的结果,done表达函数是否执行完毕。
这里的getaData就是返回的结果*/
const p1 = gen.next().value
p1.then(e => {
// 第二次next(e + 100) e + 100会传回
// 等待第一个yield的结果,这里就是a = e + 100
const p2 = gen.next(e + 100).value
p2.then(r => {
// 这里以此类推 b = r + 200
const p3 = gen.next(r + 200)
console.log(p3);
})
})
二、async函数实现
- 实现之前我们来看看要达到什么效果 也就是我们熟知的
async await的写法,除了async用*代替,await用yield代替,其他简直就是一毛一样。
// ES7 async await写法
const getData = Promise.resolve(1)
const login = Promise.resolve(2)
function async fn() {
const a = await getData;
console.log(a);
const b = await login;
console.log(b);
return 'someValue'
}
// 我们使用生成器写法 我们这样写是需要对结果进行一定的处理的
// 这就是下一步的myAsync函数实现的核心逻辑
// 也就是原生async await实现的原理
const getData = Promise.resolve(1)
const login = Promise.resolve(2)
function* fn() {
const a = yield getData;
console.log(a); // 1
const b = yield login;
console.log(b); // 2
return 'someValue'
}
/**
* 逐行解释代码
* @param {生成器函数} generator
*/
function myAsync(generator) {
// 返回函数,以防需要传参
return function () {
// 执行生成器函数 获得迭代器 gen
const gen = generator.apply(this, arguments)
if (!gen || !gen.next) throw new Error('function myAsync 参数不是生成器函数')
// Promise的作用用来处理函数的返回值
return new Promise( resolve => {
// 对出现的yield进行递归的函数
function step(gen, result) {
// 返回上一次的执行结果result 并获得下个yield
const rv = gen.next(result)
// 递归终止,使用resolve把最终return的结果返回
if (rv.done) {
resolve(rv.value)
return
}
// 获取yiled的值
const p = rv.value
// 判断是是Promise 还是普通值进行递归
p instanceof Promise ? p.then(r => {
step(gen, r)
}) : step(gen, p)
}
step(gen)
})
}
}
// 验证
const result = myAsync(fn)
三、小结
上面的代码实现的是核心代码,很多情况没有考虑,也没有错误处理,但是能很好看出生成器是怎么工作的,以及巧妙的借用它实现async 和await。
PS:第一次码文章,有什么建议欢迎留言。