什么是async?
async 函数是 Generator 函数的语法糖。使用 关键字 async 来表示,在函数内部使用 await 来表示异步 ,async 函数返回值是 Promise 对象
如果async关键字函数 return 的不是promise,会自动用Promise.resolve()包装 如果async关键字函数显式地 return 一个 promise,那就以你返回的promise为准
- async与普通函数
async function fn1(){
return 123
}
function fn2(){
return 123
}
console.log(fn1())
console.log(fn2())
// 输出
Promise {<resolved>: 123}
123
- async返回promise
async function asyncFn() {
return '1'
}
asyncFn().then(result => {
console.log(result);
})
console.log('2');
// 输出
2 1
失败
async定义的函数内部会默认返回一个promise对象,但是返回如下结果会使async函数判定失败reject:
- 内部含有直接使用并且未声明的变量或者函数。
- 内部抛出一个错误
throw new Error或者返回reject状态return Promise.reject('执行失败') - 函数方法执行出错(Object使用push())等
await是什么?
await 只能在使用async定义的函数里面使用。async函数必须等到内部所有的 await 命令的 Promise 对象执行完,才会发生状态改变。 正常情况下,await 命令后面跟着的是 Promise ,如果不是的话,也会被转换成一个 立即 resolve 的 Promise
await 在等什么
await等的是右侧「表达式」的结果
在等到结果之前,await 会阻塞后面的代码
但是,async函数中若某个await的 Promise 对象状态变为rejected,后续代码不会执行
async function asyncFn() {
await Promise.reject("1");
console.log("2"); // 不会执行
}
asyncFn()
.then(result => {
console.log(result);
})
.catch(error => console.log(error));
console.log('3');
// 输出 3 1
await 执行顺序
await是从右往左执行的
await是从右往左执行的
await是从右往左执行的
重要的事情说三遍,这个对于细节理解很重要
什么时候产生阻塞
在遇到 await 的时候,才会发生阻塞. 但由于是从右往左,所以
await 右侧的代码会先执行
await 右侧的代码会先执行
await 右侧的代码会先执行
右侧先执行,因为前面有 await,所以会阻塞执行结果,将结果放入微任务中!
阻塞什么时候恢复
这要取决于 await 右侧的执行结果是什么
- promise对象
- 非promise对象
-
如果 await 等到的是一个 promise 对象,await 也会暂停 async 后面的代码,先执行 async 外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。
-
如果不是 promise , await 会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到 async 内部,把这个非promise的东西,作为 await 表达式的结果
- await与非promise
async function asyncFn() {
await "1";
console.log("2");
}
asyncFn()
.then(result => {
console.log(result);
})
console.log('3');
// 输出3 2 undefined
分析
- 开始执行
asyncFn(),从右到左执行到await "1",此时"1"等价于Promise.resolve("1"),所以函数相当于:
async function asyncFn() {
await Promise.resolve("1");
console.log("2");
}
asyncFn()
.then(result => {
console.log(result);
})
console.log('3');
因为从右到左执行,所以先执行 Promise.resolve("1"),该 Promise 状态变为 fulfilled
-
执行到 await,阻塞 async 后面的代码,跳到外层执行同步代码,
输出 3 -
同步代码执行完毕,微任务里没有任务,检查 await,发现右侧是一个已经 fulfilled 的 Promise(fulfilled),所以取消阻塞,继续向下执行,
输出 2 -
继续执行,asyncFn执行结束,没有返回值,相当于 返回了一个 Promise.resolve(),所以 asyncFn() 其后的
then(result => { console.log(result); })被压入微任务栈 -
继续执行,发现没有同步代码了, 轮询微任务队列,执行
console.log(result);,输出 undefined
- async 与 promise 将上述例子稍微变动一下,加个promise看看
async function asyncFn() {
await "1";
console.log("2");
}
asyncFn()
.then(result => {
console.log(result);
})
new Promise((resolve, reject) => {
resolve(4);
}).then(data => {
console.log(data);
})
console.log('3');
// 输出 3 2 4 undefined
分析
-
开始执行
asyncFn(),从右到左执行到await "1",此时阻塞 async 后的代码执行 -
跳到外层执行同步代码,执行
resolve(4),其后的then(data => { console.log(data); })被压入微任务栈 -
继续执行同步代码,
输出3 -
回到 await,取消其阻塞,执行async 后面代码,
输出2 -
轮询微任务队列,里面有两个微任务,按照顺序执行,
输出 4,随后输出 undefined,注意这里不是输出两个 undefined
- async 与 微任务栈 下面的例子,与微任务栈的理解强相关。希望读者先有一个准确的概念
当你在某次微任务中,引发了新的微任务,这个微任务虽然是被压入了微任务栈,但它与当前的微任务并不在同一次轮询当中
async function asyncFn() {
await func();
console.log("asyncFn1");
return "asyncFn2"
}
function func(){
console.log("asyncFn3");
return new Promise((res,rej)=>{
res('asyncFn4');
})
.then(data => {console.log(data); return 'asyncFn5'})
.then(data => {console.log(data)})
}
asyncFn()
.then(data => {
console.log(data);
})
new Promise((resolve, reject) => {
resolve('promise1');
}).then(data => {
console.log(data);
return 'promise2'
}).then(data => {
console.log(data);
return 'promise3'
}).then(data => {
console.log(data)
})
// 输出
asyncFn3
asyncFn4
promise1
asyncFn5
promise2
asyncFn1
promise3
asyncFn2
分析
- 开始执行
asyncFn(),从右到左执行到await func();,执行 func,输出asyncFn3 - 继续执行, return promise,此时继续执行promise,
res('asyncFn4')执行,该promise状态变为resolved,其回调.then压入微任务栈(微任务1),func()执行结束 - await 阻塞 async 后的代码执行,跳到外层执行同步代码,执行
resolve('promise1');,其回调.then压入微任务栈(微任务2) - 同步代码执行完毕,轮询微任务栈
- 微任务1
输出asyncFn4,其回调then压入微任务栈(微任务3) - 微任务2
输出promise1,其回调.then压入微任务栈栈(微任务4) - 第一轮微任务轮询结束,检查同步代码,没有需要执行的,继续轮询微任务栈
- 微任务3
输出asyncFn5, - 微任务4
输出promise2,其回调.then压入微任务栈(微任务5) - 第二轮微任务轮询结束,检查同步代码,await 等待的promise状态已经变成 resolved,变为非阻塞状态,执行同步代码,输出
asyncFn1,asyncFn 状态变为 resolved,其回调.then压入微任务栈(微任务6) - 同步任务结束,微任务5,
输出promise3 - 微任务6,
输出asyncFn2
- async 与 宏任务
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
setTimeout(function() {
console.log("setTimeout");
}, 0);
async1();
new Promise(function(resolve) {
console.log("promise1");
resolve();
}).then(function() {
console.log("promise2");
});
// 输出
async1 start
async2
promise1
async1 end
promise2
setTimeout
魔鬼训练
const timeoutFn = function(timeout){
return new Promise(function(resolve){
return setTimeout(resolve, timeout);
});
}
async function fn(){
await timeoutFn(1000);
await timeoutFn(2000);
return '完成';
}
fn().then(success => console.log(success));
console.log('2');
// 先输出2,3s后输出完成
const timeoutFn = function(timeout){
return new Promise(function(resolve){
return setTimeout(resolve, timeout);
});
}
const timeoutFn2 = function(timeout){
return new Promise(function(resolve){
return setTimeout(console.log(timeout), timeout);
});
}
async function fn(){
await timeoutFn(1000);
await timeoutFn2(2000);
return '完成';
}
fn().then(success => console.log(success));
console.log('2');
// 先输出2,1s后输出2000,由于timeoutFn2状态一直未变成fulfilled,所以不会输出完成
const timeoutFn = function(timeout){
console.log(timeout);
return new Promise(function(resolve){
return setTimeout(()=>{
console.log("resolve in")
resolve();
}, timeout);
});
}
async function fn(){
await timeoutFn(1000);
console.log("第一个完成");
await timeoutFn(2000);
return '完成';
}
fn().then(success => console.log(success));
// 输出1000,等待1s,输出resolve,第一个完成,2000,等待2s,输出resolve,完成
function timeout(time){
return new Promise(function(resolve){
return setTimeout(function(){
return resolve(time + 1000)
},time);
})
}
function first(time){
console.log('第一次延迟了' + time );
return timeout(time);
}
function second(time){
console.log('第二次延迟了' + time );
return timeout(time);
}
function third(time){
console.log('第三次延迟了' + time );
return timeout(time);
}
async function start() {
console.log('START');
const time1 = 1000;
const time2 = await first(time1);
const time3 = await second(time2);
const res = await third(time3);
console.log(`最后一次延迟${res}`);
}
start();
async function testSometing() {
console.log("testSomething");
return "return testSomething";
}
async function testAsync() {
console.log("testAsync");
return Promise.resolve("hello async");
}
async function test() {
console.log("test start...");
const testFn1 = await testSometing();
console.log(testFn1);
const testFn2 = await testAsync();
console.log(testFn2);
console.log('test end...');
}
test();
var promiseFn = new Promise((resolve)=> {
console.log("promise START...");
resolve("promise RESOLVE");
});
promiseFn.then((val)=> console.log(val));
console.log("===END===")
//输出
test start...
testSomething
promise START...
===END===
return testSomething
testAsync
promise RESOLVE
hello async
test end...