走起,来吧少年
1、基本原理
async / await 本质上就是 generator 的语法糖
- 内置执行器,无需手动执行 next() 方法
2、generator
- 在了解async 和 await 之前我们先来了解的下generator函数 (es6.ruanyifeng.com/#docs/gener…
- ES6 新引入了 Generator 函数,可以通过 yield 关键字,把函数的执行流挂起,通过next()方法可以切换到下一个状态,为改变执行流程提供了可能,从而为异步编程提供解决方案。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
const hw = helloWorldGenerator();
hw.next() // { value: 'hello', done: false }
hw.next() // { value: 'world', done: false }
hw.next() // { value: 'ending', done: true }
hw.next() // { value: undefined, done: true }
复制代码
*/yield
和async/await
看起来其实已经很相似了- 但是
Generator
的特点:Generator
返回的是生成器对象- 需要手动调用
next()
才能执行下一步
- 回想
async
和await
的特点、async/await
自带执行器,不需要手动调用next()
就能自动执行下一步async
函数返回值是Promise
对象await
能够返回Promise
的resolve/reject
的值
- 基于对Generator的理解,我们可以封装一个伪函数
3、async 和 await模拟实现
要想实现async
和 await
的功能我必须先解决Generator
自动执行问题
function* myGenerator() {
const res1 = yield Promise.resolve(1);
console.log('res1', res1); // 1
const res2 = yield Promise.resolve(2);
console.log('res2', res2); // 2
const res3 = yield Promise.resolve(3);
console.log('res3', res3); // 3
}
// 手动执行迭代器
const gen = myGenerator()
gen.next().value.then(val => {
gen.next(val).value.then(val => {
gen.next(val).value.then(val => {
gen.next(val)
})
})
})
复制代码
看到myGenerator
有点async 和 await 的感觉了, 但是上面的手动执行代码显得笨拙且复用性不好,据此,我们把上面代码封装下成一个自动执行函数
function runGenerator(gen) {
var g = gen() //由于每次gen()获取到的都是最新的迭代器,因此获取迭代器操作要放在_next()之前,否则会进入死循环
function _next(val) { //封装一个方法, 递归执行g.next()
var res = g.next(val) //获取迭代器对象,并返回resolve的值
if(res.done) return res.value //递归终止条件
res.value.then(val => { //Promise的then方法是实现自动迭代的前提
_next(val) //等待Promise完成就自动执行下一个next,并传入resolve的值
})
}
_next() //第一次执行
}
复制代码
然后基于上面的函数改写后
function* myGenerator() {
const res1 = yield Promise.resolve(1);
console.log('res1', res1); // 1
const res2 = yield Promise.resolve(2);
console.log('res2', res2); // 2
const res3 = yield Promise.resolve(3);
console.log('res3', res3); // 3
}
const gen = runGenerator(myGenerator); //
console.log(gen); //undefined (还需要实现返回promise)
复制代码
- 这样我们就初步实现了一个async/await。
- 简单说就是封装一个自动
generator
的next()
的方法,每次Promise.then()的时候都去执行_next(),实现自动迭代的效果。
4、返回promise和异常处理
基于上面代码还存在3个问题
- 自动执行函数需要返回一个promiseduixiang
- yield后面目前跟的是Promise.resove(),我们需要支持普通的级别类型值
- 异常的处理
function runGenerator(gen) {
//把返回值包装成promise
return new Promise((resolve, reject) => {
var g = gen()
function _next(val) {
//错误处理
try {
var res = g.next(val)
} catch(err) {
return reject(err);
}
if(res.done) {
return resolve(res.value);
}
//res.value包装为promise,以兼容yield后面跟基本类型的情况
Promise.resolve(res.value).then(
val => {
_next(val);
},
err => {
//抛出错误
g.throw(err)
});
}
_next();
});
}
复制代码
然后再次执行下
function* myGenerator() {
try {
const res1 = yield Promise.resolve(1);
console.log('res1', res1); // 1
const res2 = yield 2;
console.log('res2', res2); // 2
const res3 = yield Promise.reject('error');
console.log('res3', res3); // 3
} catch (error) {
console.log(error)
}
}
const gen = runGenerator(myGenerator);
console.log(gen); //promise
//输出 1 2 error
复制代码
- 好了,今天就介绍到这里,下面我来总结下今天的主要内容。
- Promise 的编程模型依然充斥着大量的 then 方法,虽然解决了 回调地狱 的问题,但是在语义方面依然存在缺陷,代码中充斥着大量的 then 函数,这就是 async / await 出现的原因。
- 使用 async/await 可以实现用同步代码的风格来编写异步代码,这是因为 async/await 的基础技术使用了
generator
和Promise
1、结语
感谢各位老铁,点赞加关注
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END