async函数 – 异步函数
作用
- ES2017推出的一种新的处理异步请求方法,是generator的语法糖(generator的优化),可以用来轻松定义异步函数
对比generator
-
async 取代 *
-
await 取代 yield
-
async不需要自己手动移动指针,它会自动执行,如果在某个阶段执行失败则会终止执行后面的任务,而generator需要手动调用next()一步步执行
-
await右边是表达式或语句,如果它返回不是Promise对象会调用Promise.resolve(),把这个值转换成状态为re,如果是promise对象,返回resolve()语句执行时传入的实参
async function foo1(){
let a = await 1+3;
let b = await add(2,4);
console.log(a); //4
console.log(b); //6
}
async function foo2(){
let a = await Promise.resolve('1');
let b = await Promise.resolve('2');
console.log(a); //1
console.log(b); //2
}
// await执行的是异步任务,他会在主线程后执行
foo1();
foo2();
//await执行的异步操作,会先输出3
console.log(3);
// 3
// 4
// 6
// 1
// 2
foo1()里的 4, 6 都会先转换为Promise对象,并且把返回7与对应promise对象调用resolved()回调函数时传入的参数相同的值(有点绕~)
async function foo3(){
let a = await 1+3;
return a;
}
async function foo3(){
let a = 1+3;
return a;
}
foo3();
foo4();
- async 函数始终返回一个promise对象,就算不是也会包装成一个promise对象,并且该对象的状态是fulfilled
async function foo3() {
return await 1 + 3; // 尝试解包promise对象, 返回resolve传入的实参
}
async function foo4() {
return 1 + 3; // 直接返回的话不会解包,返回Promise对象
}
async function foo5() {
console.log(1 + 3); // 直接返回的话不会解包,返回Promise对象
}
console.log(foo3()); // Promise{fulfilled: 4}
console.log(foo4()); // Promise{fulfilled: 4}
console.log(foo5()); // Promise{fulfilled: undefined}
foo3() 里的await在return命令中,按上面的foo1()的道理应该返回一个数值4,但是返回的确实Promise对象,为啥?其实这里没有矛盾,而是里面有两步操作,await返回的确实是数值4,但是aysnc返回的必须是一个Promise对象,所以又会把数值4封装成一个Promise对象。
foo5()没有返回值,所以PromiseResult为 undefined
- aysnc 只是一个标识符,真正起作用的应该是 await,如果一个异步函数没有await,他跟同步函数没有啥区别
- await 不仅仅是等待一个值那么简单,当js运行时遇到了await关键字,会记录停止的位置,等到值求得后,js运行时会向消息队列推送一个任务,这个任务会恢复异步函数的执行
- 即使 await 后面跟着一个立即可用的值,函数的其余部分也会被异步求值。
async function foo() {
console.log(2);
await null;
console.log(4);
}
console.log(1);
foo();
console.log(3);
// 1
// 2
// 3
// 4
console.log(4)应该是立即执行函数,但是却在console.log(3)后面执行,这正是前面有await命令,是的console.log(4)变成了异步任务
- 上面函数的执行过程
// (1) 打印 1;
// (2) 调用异步函数 foo();
// (3)(在 foo()中)打印 2;
// (4)(在 foo()中)await 关键字暂停执行,为立即可用的值 null 向消息队列中添加一个任务;
// (5) foo()退出;
// (6) 打印 3;
// (7) 同步线程的代码执行完毕;
// (8) JavaScript 运行时从消息队列中取出任务,恢复异步函数执行;
// (9)(在 foo()中)恢复执行,await 取得 null 值(这里并没有使用);
// (10)(在 foo()中)打印 4;
// (11) foo()返回。