async关键字用于声明一个函数是异步的,搭配await实现函数的异步执行,在async函数中,如果没有await关键字,则函数与普通函数没有什么区别,函数代码将会同步执行。
当异步函数有返回值时,和普通的函数会有区别。
1、异步函数也可以有返回值,返回值会包裹到Peomise.resolve中。
2、如果异步函数返回的是一个Promise,Promise.resolve的状态将会由Promise决定。
3、如果异步函数的返回值实现了thenable,那么会由返回值的then来决定。
如果在async中抛出了异常throw,那么函数不会像普通函数一样报错,而是会作为Peomise的reject来传递错误信息。
await关键字在普通函数中不可以使用,在await关键字后会返回一个promise,await会等到promise变成fulfilled状态时,之后继续执行异步函数。
- 如果await后是一个普通的值,那么会直接返回这个值。
- 如果await后是一个thenable对象,那么会根据对象的then方法来决定后续的值。
- 如果await后面的表达式返回的是reject状态,那么会将这个reject结果作为函数的promise的reject值。
事件循环:
js主线程执行同步代码,将异步代码交由其它线程执行,其它线程执行完毕后将异步代码添加到事件队列中,js引擎定时执行事件队列中代码,将代码放入js线程中执行。
宏任务队列-----macrotask queue---定时器-Ajax-dom-ui rendering
微任务队列-----microtask queue---queueMicrotask--- promise then
规范:在执行宏任务之前需保证微任务队列已经清空。
面试题一:
setTimeout(function () {
console.log("setTimeout1");
new Promise(function (resolve) {
resolve();
}).then(function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log('then2');
})
})
new Promise(function (resolve) {
console.log('promise1');
resolve();
}).then(function () {
console.log("then1");
})
setTimeout(function () {
console.log("setTimeout2");
})
console.log(2);
queueMicrotask(() => {
console.log("queueMicrotask1");
})
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then3");
})
上题中按照jsv8引擎的执行逻辑,promise原理及实现不难得出函数的输出结果,按照mainscript-->microltask--->macroltask顺序执行。
面试题二:
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => {
console.log('settimeout');
}, );
async1();
new Promise((resolve, reject) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise2');
})
此题关键在于了解async的特性及await关键字的作用,在含有await的async中,同一代码块中await后的所有代码将被放置返回的promise的then方法中执行,也即await后的代码将被加载进微任务队列,同时不含await的async函数与普通函数没有任何差别,由此不难得出结果为:
面试题三:
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);
}).then(() => {
console.log(7);
})
此题主要注意的是原生的Promise的then方法中,如果返回的是一个普通值,则返回的值会被立即调用并赋值给resolve函数,如果返回的是一个thenable,则then方法将会被放入到微队列中执行,如果返回的是一个Promise.resolve,则会再加一次微任务队列。即微任务后移,Promise.resolve本身是执行then方法,而then方法本身是在微任务队列中执行,同时return Promise.resolve时是将resolve调用的返回值 作为上级then中resolve的参数传递,调用外层then方法时本身是在微队列里面,所以函数的执行顺序是要在微队列中下移两次。