promise和setTimeout都是处理异步回调的,那么到底谁先谁后呢?
我们来看一个例子:
(function test() {
setTimeout(function() {console.log(1)}, 0);
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
})()
答案是 2 3 5 4 1,而且在控制台编译的时候,看到1和其他的数字不同,函数的返回值都出现了才执行。那么,为什么会这样呢?
当我们执行JS代码的时候,遇到异步代码时,会被挂起并加入到Task队列中。当执行栈为空的时候,就在Task队列中拿出需要执行的代码。不同的任务会被分配到不同的队列,我们可以把它分为 微任务(microtask) 和 宏任务(macrotask)。
- 微任务包括
process.nextTick
,promise
,MutationObserver
。 - 宏任务包括
script
,setTimeout
,setInterval
,setImmediate
,I/O
,UI rendering
。
浏览器的执行Even Loop执行顺序如下:
- 首先执行同步代码,这也属于宏任务。
- 执行完同步代码后,查询是否有宏任务中的异步代码需要执行。(这个时候只是查询,并没有执行哦)
- 执行完所有的微任务,并完成页面渲染
- 开始下一轮EventLoop
- 如果 2 步骤中查询到要执行的异步代码,这时候执行。如setTimeout函数
这样,上图的情况就能解释了。