Promise和setTimeout执行顺序的问题

4/2/2019 Promise

Promise为es6引进的语言标准,为异步编程的一种解决方案; 阅读此文的前提是了解浏览器event loop的机制,还有promise的基本用法和特性,比如他自执行特性、状态不可逆特性等

# 抛出问题

来看下面代码的问题

setTimeout(function(){console.log(1)},0)
new Promise(function(resolve){
    console.log(2)
    for(var i = 0; i<10000; i++ ){
       i==999&& resolve()
    }
    console.log(3)
}).then(function(){
    console.log(4)
})
console.log(5)
// 这的问题是为什么答案是 2 3 5 4 1
// 而不是 2 3 5 1 4 呢
1
2
3
4
5
6
7
8
9
10
11
12
13

既然promise.then和setTimeout都是异步的,那么在时间循环队列中promise.then的事件应该排在setTimeout后面,而为什么promise.then却在setTimeout前面被打印了出来?

# 重要概念

event loop的概念
1.JavaScript是单线程的,所有的同步任务都会在主线程中执行。
2.当主线程中的任务,都执行完以后,系统会"依次"读取任务队列里的事件。与之相对应的异步任务进入主线程,开始执行。
3.异步任务之间,会存在差异,所以它们执行的优先级也会有区别,大致分为 微任务(microtask,如:Promise、MutaionObserver等)和 宏任务(macro task,如:setTimeout、setInterval、I/O等)。
4.Promise执行器中的代码会被同步调用,但是回调是基于微任务的。
5.宏任务的优先级高于微任务。
6.每一个宏任务执行完毕都必须讲当前的微任务队列清空
7.第一个script标签的代码是第一个宏任务。
8.主线程会不断重复上面的步骤,直到执行完所有任务。

# 我的理解

我们来捋一遍代码的执行过程哈。
所有的代码都写在script标签中,所以读取所有代码是第一个宏任务,我们开始执行第一个宏任务。
我们首先遇到setTimeout,他是第二个宏任务,将它扔进宏任务事件队列里先排队。
下来我们遇到了promise,promise执行器里的代码会被同步调用,所以我们依次打印出2和3。
下来遇到了promise的回调,它是一个微任务,将它扔进微任务事件队列中。
下来我们接着打印出5,然后执行微任务并且打印出4。
我们第一个宏任务执行完毕,执行下一个宏任务,打印出1,到此,所有任务都执行完毕。
所以我们最后的结果为2 3 5 4 1。