“种一棵树的最好时间是十年前,其次是现在” ————致迷茫中的少年
前情提要
想要解决绝大多数Promise相关的面试题首先你得知道下面几个知识点
- 1、JavaScript的运行模式
- 2、EventLoop事件循环和事件队列
- 3、宏任务和微任务
- 4、async和await
知识点概述
具体知识点大家可以看一下其他大佬的文章,掘金里有很多都说的都非常好
Js的运行模式:
简言之,记住浏览器是多线程的但js的执行环境是单线程的,就像是一条流水线,按照顺序依次的执行相关任务
EventLoop事件循环和消息队列
- 1、执行栈中的同步任务进入主线程,异步任务进入Event Table并注册函数再放进EventQueue(消息队列:存放异步任务的地方)
- 2、主线程内的任务执行完毕后,会去EventQueue读取对应的函数,进入主线程执行。
- 3、再重复步骤1,如此往复循环
宏任务和微任务
-
宏任务:
script标签 setTimeout setInterval setImmediate ... -
微任务
原生Promise(有些实现的promise将then方法放到了宏任务中) process.nextTick MutationObserver
async和await
- async 返回的是一个promise对象
- await 如果产出的是一个promise 会调用这个promise.then方法,await会阻塞后面代码的执行
解题技巧
记住下面的顺序
1.从上往下执行代码
2.同步任务直接执行,遇到异步任务将宏任务放进宏任务队列微任务放到微任务队列
3.当同步任务执行完毕后,先将微任务放入主线程执行
4.最后将宏任务放入主线程执行
注意:
1.await 会阻塞后面代码的执行,做题时await后面的代码可以看做是一个微任务放入微任务队列
2.Promise状态为padding时候不会执行.then()或.catch()方法
面试题
//请写出输出内容
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
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
async2
promise1
script end
async1 end
promise2
setTimeout
注意: 队列是先进先出
解析:
1.代码由上而下执行,首先执行同步代码输出“script start”
2.遇到宏任务setTimeout()放入宏任务队列
3.执行async1(),输出“async1 start”
4.执行await async2()并将后面的代码阻塞,可以看做是放入微任务队列
5.输出“async2”
6.async()执行完成后跳出,继续执行执行栈中的同步任务
7.执行new Promise()中的代码,输出“promise1”
8.执行resolve()后,Promise的状态变为padding
9.遇到.then()方法,放入微任务队列等待执行
10.执行主线程中最后一个同步任务 输出“script end”
11.将微任务队列中的任务放到主线程执行,先输出“async1 end”
12.主线程中的任务执行完后,再去微任务队列看还有一个.then(),把它移入主线程执行,输出“promise2”
13.主线程任务执行完后再去微任务队列,微任务队列没有任务了,再去宏任务队列执行setTimeout(),输出“setTimeout”
第一次写,写这个也花了挺久的时间,有错误的话望大佬指点一下