async和await的基本使用
async和await师异步编程的一种解决方案,它的出现使得异步操作变得更加方便。但async说到底其实就是Generator的语法糖。比起generator,async有着四点不同:
- 内置执行器:这个执行器可以使得generator函数自动执行next方法,不同自己调用。
- 语义更清楚:async相当于generator的 * 符号,代表函数内部有异步操作,await则相当于yield,代表紧跟在后面的表达式需要等待结果。
- 适用性更广泛:yield后面只能跟Trunk函数和Promise对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
- 返回值师Promise:async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。
基本用法
async声明,await后跟执行的表达式,因为返回的是Promise,所以可以调用then方法,
一但函数内部遇到await,则会立即跳出函数,并返回一个Promsie,继续执行函数外的语句(执行主执行栈的语句),等执行栈语句全部清空后再执行await后的异步语句执行完再继续执行await后面的语句。
async function test2() {
setTimeout(_=>{
console.log(1);
})
}
async function test1() {
console.log("a");
let a = await test2();
console.log("d");
}
let c = test1();
console.log("c");
// a c d 1
上述代码会先打印a,然后执行test2,遇到异步setTimeout,跳出函数,打印c,之后再打印d,最后打印1。
async实现原理
async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。
async function fn(args) {
// ...
}
// 等同于
function fn(args) {
return spawn(function* () {
// ...
});
}
spawn就是一个自执行器。
spawn实现
function spawn(genF) {
//返回一个Prommise
return new Promise(function(resolve, reject) {
//gen为genF的遍历器对象
const gen = genF();
//step函数为判断是否继续调用next方法
//回调函数nextF回调用于获取执行next后的对象
function step(nextF) {
let next;
try {
next = nextF();
} catch(e) {
return reject(e);
}
//判断遍历器对象是否全部遍历完成
if(next.done) {
//如果完成,则返回Promise成功的状态,并将返回值传入
return resolve(next.value);
}
//递归调用step,直到Generator全部执行完成。
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
//开始调用step方法
step(function() { return gen.next(undefined); });
});
}