Promise,async和await的面试题
async和await的基本原理
async
async
是Generator
函数的语法糖,使用async
表示,在函数内部使用await
表示异步,相对于Generator
,async
做了一些改进:
Generator
的执行需要依靠执行器,async内置执行器,自动执行async
代替了*
,await
代替了yield
,语义化更好async
函数返回值是一Promise
对象
await
await
意思是async wait(异步等待)。这个关键字只能在使用async
定义的函数里面使用。await会解析Promise对象的值,async
会等所有的await
命令的Promise
对象执行完,才会发生状态的改变。
一、关于Promise的执行顺序
创建Promise是同步的,当执行完resolve();
后,状态变为resolved
,后面的.then
立即放入微队列,第二个.then
放入第一个.then
返回promise对象的缓存队列中(并不是微队列)。
1.
new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
})
.then(() => {
console.log("外部第一个then");
return new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
})
.then(() => {
console.log("内部第一个then");
})
.then(() => {
console.log("内部第二个then");
});
}) 这里返回的对象是最后一个.then返回的对象,第一次时状态为‘pending’
.then(() => { 所以第一次这里会缓存起来并不是加入队列
console.log("外部第二个then");
});
2.
new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
})
.then(() => {
console.log("外部第一个then");
new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
})
.then(() => {
console.log("内部第一个then");
})
.then(() => {
console.log("内部第二个then");
});
}) 这里返回的是undefined 的promise对象
.then(() => { 第一次时这个promise对象已经是resolved了,所以立即加入队列
console.log("外部第二个then");
});
3.
console.log(1);
setTimeout(() => {
console.log(2);
});
new Promise(resolve => {
console.log(3);
resolve('resolve');
console.log(4);
reject('error')
}).catch((err) => {
console.log(err);
}).then((res) => {
console.log(res)
});
Promise.resolve().then(() => {
console.log(5);
});
console.log(6);
执行catch时,状态已经变为resolved,就不会执行catch的回调函数,而执行默认的成功的回调函数:onResolved : value => value
。一定要注意这里直接把catch的回调函数替换了,所以不会再执行console.log(err);
了。
1
3
4
6
5
resolve
2
4.
console.log('start');
setTimeout(() => {
console.log('time');
});
const p1 = new Promise((resolve, reject) => {
console.log('resolve1');
}).then(() => {
console.log('resolve');
});
console.log('end');
start
resolve1
end
time
由于没有调用resolve
,所以该promise
函数一直处于pending
状态,并不会执行.then
函数。
二、关于async和await
async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回(交出线程,跳出 async 函数体),等到触发的异步操作完成,再接着执行函数体内后面的语句。
await后面的语句会立即执行,返回promise时,由于考虑到异步操作,且下一行语句需要知道结果才能执行,所以返回的promise会等后面的同步语句执行完之后放入微队列中。
1.
async function async1(){
console.log('async1 start');
await async2(); 会先执行async2函数,然后跳出async1,执行同步语句,然后将返回的promise放入微队列
// 会立即放入微队列,相当于.then,所以会在promise2的前面
console.log('async1 end');
}
async function async2(){
console.log('async');
}
console.log('script start');
setTimeout(function (){
console.log('setTimeout');
},0);
async1();
new Promise(function(resolve){
console.log('promise1');
resolve();
}).then(function(){
console.log('promise2');
});
console.log('script end');
script start
async1 start
async
promise1
script end
async1 end
promise2
setTimeout
2.
async function async1() {
console.log('async1 start');
const result = await async2();
console.log(result);
// 会先执行async2函数, 然后跳出async1, 同时将返回的promise放入微队列
console.log('async1 end');
}
async function async2() {
console.log('async');
return "testAwait";
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
new Promise(function(resolve) {
console.log('promise3');
resolve();
}).then(function() {
console.log('promise4');
});
console.log('script end');
script start
async1 start
async
promise1
promise3
script end
promise2
promise4
testAwait
async1 end
setTimeout
三、Promise.resolve()会造成三次微队列入队延迟
先来看一段代码,下面这段代码输出 0,1,2,3,4,5,6
Promise.resolve().then(() => {
console.log(0);
return Promise.resolve(4);
}).then((res) => {
console.log(res);
});
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() => {
console.log(6);
});
参考博文:
[1]: https://juejin.cn/post/6844903621360943118