1.介绍
- 它是使用了Generator函数基于Promise的封装,是Promise的一个语法糖;
- 它是一种异步编程的解决方案,可以以同步的代码方式来写异步;
- await关键字可以“暂停”async function的执行;
可以用try-catch捕获到async function所得到的错误;
2.基本使用
声明两个promise对象:
const promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve(1)}, 500)})const promise2 = new Promise((resolve, reject) => {setTimeout(() => {reject(2)}, 500)})
传统的方式:
promise1.then(res => {console.log(res); // 1})promise2.catch(res => {console.log(res); // 2})
async await方式:
async function asyncFunc(){const res = await promise1;console.log(res); // 1try{const res = await promise2;} catch(err) {console.log(err); // 2}}asyncFunc();
3.进阶使用
场景:要做三件事,下一件事依赖上一件事返回的结果;
假设:dosomething返回的是Promise;
处理顺序:dosomething1 => dosomething2 => dosomething3;// 传统的方式 (可以看到存在多重嵌套,错误处理也需要单独写)dosomething1().then(res1 => {dosomething2(res1).then(res2 => {dosomething3(res2).then(res3 => {console.log(res3)})})})// async await方式 (没了嵌套,简洁了)try {const res1 = await dosomething1();const res2 = await dosomething1(res1);const res3 = await dosomething1(res2);console.log(res3)} catch (error) {console.log(error) // 统一捕获错误}
注意,如果每件事没有相互之间的依赖,使用了上面的那种方式后,会增加得到结果的时间(明明可以并行处理的,但是变成了串行);可以考虑使用Promise.all来执行:
const [res1, res2, res3] = await Promise.all([dosomething1(), dosomething2(), dosomething3()])
4.原理解读
Generator函数
Generator 函数,可以通过 yield 关键字,把函数的执行流挂起,通过next()方法可以切换到下一个状态,可以控制代码执行流程(暂停和继续),从而为异步编程提供解决方案。
基本使用:function* myGenerator() {yield '1'yield '2'return '3' // 到return这步,done为true;}const gen = myGenerator(); // 获取迭代器gen.next() //{value: "1", done: false}gen.next() //{value: "2", done: false}gen.next() //{value: "3", done: true}
可以通过给next()传参, 让yield具有返回值:
function* myGenerator() {console.log(yield '1') //res1console.log(yield '2') //res2console.log(yield '3') //res3}// 获取迭代器const gen = myGenerator();gen.next()gen.next('res1')gen.next('res2')gen.next('res3')
await async的规范
async函数会自动返回一个Promise对象;
- await关键字能够返回Promise的resolve的值;
-
实现思路
相同:可以看到 */yield和async/await这两个关键词有点类似的;
- 不同:await每一步可以自动执行,不需要手动调用next()就能自动执行下一步;
- 不同:asnyc返回的是一个Promise, Generator函数返回的是一个迭代器对象;
所以我们需要封装一个返回Promise对象的并且可以自动执行的Generator函数的函数:
//通过包一层runAsync函数 模拟await asyncfunction* asyncFn() {try {var a = yield 1; // next()返回 { value: 1, done: false }var b = yield Promise.resolve(++a); // next()返回 { value: Promise.resolve(++a), done: false }//throw Error();var c = yield Promise.resolve(++b); // next()返回 { value: Promise.resolve(++b), done: false }console.log(c); // 3return c; // next()返回 { value: 3, done: false }} catch (error) {console.log(error,"error")}}function runAsync(asyncFn) {let g = new asyncFn();// async返回的是一个Promisereturn new Promise((resolve, reject) => {// 实现自动执行的方法function _next(val) {try {var res = g.next(val); //得到Generator对象: {value: xxx, done: xxx}} catch (error) {// 防止yield执行过程成抛出错误reject(error);return;}// 执行到最后;退出自动执行if (res.done) return resolve(res.value);// 自动执行下一个yield// 包一层Promise是为了兼容yield后面不是跟Promise对象的情况;Promise.resolve(res.value).then((data) => {_next(data);},(err) => {g.throw(err); // 给外面的try catch捕获});}_next();});}// 执行asyncFn,模拟的async await函数执行流程;let p = runAsync(asyncFn);p.then(res => {console.log(res) // 3}).catch((err) => {console.log(err);});
