最近面试遇到这样一道面试题:
console.log(1);
setTimeout(()=> {
console.log(2);
},1000);
setTimeout(() => {
console.log(3);
},0);
new Promise((resolve, reject) => {
console.log(4);
resolve();
}).then(() => {
console.log(5);
}).then(() => {
console.log(6)
})
console.log(7);
new Promise((resolve, reject) => {
console.log(8);
resolve();
}).then(() => {
console.log(9);
}).then(() => {
console.log(10)
})
问:上述代码的输出结果是啥?
答:1、4、7、8、5、9、6、10、3、2
为什么输出结果是上边这样的顺序呢?promise的then回调函数会在setTimeout(function () {}, 0);
之前输出呢?我们可以先从事件循环说起:
Javascript是单线程的,在执行时,会先执行同步代码,遇到异步执行的代码,会先将代码放入到任务队列中,主线程的代码执行完毕,就会从任务队列中取出任务执行。 按照当前描述,Javascript会先执行同步代码,即console.log()函数和promise实例对象
;然后,将其余的异步函数加入到任务队列中。
接下来,promise的then回调和setTimeout函数,都是异步执行,那么为什么promise的then回调会在setTimeout之前输出呢?原因如下:
在JavaScript中,任务队列不止有一个,包含:MacroTask和MicroTask,在Javascript中可以包含多个MacroTask,但是只能包含一个MicroTask,在代码执行中,异步事件会根据自己的类型加入到不同的任务队列中。
Javascript开始执行事件时,会先清空函数调用栈,然后先执行MicroTask任务,再执行MacroTask;在执行这两个任务队列时,会先将MicroTask任务队列清空,然后再去执行MacroTask队列中的一个。然后循环执行…
MicroTask: Promise、Object.observe
MacroTask: setTimeout、setInterval、setImmediate、UI渲染