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); // 1
try{
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') //res1
console.log(yield '2') //res2
console.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 async
function* 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); // 3
return c; // next()返回 { value: 3, done: false }
} catch (error) {
console.log(error,"error")
}
}
function runAsync(asyncFn) {
let g = new asyncFn();
// async返回的是一个Promise
return 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);
});