8

理解Promise的执行顺序,需要一些背景知识作为前提:
1:每一个当下,正在被执行的JS代码是放在JS的主线程(我们叫JS Stack)的。同步的代码会按照代码顺序依次放入JS Stack,然后按照放入的顺序依次执行。

2:异步的代码会被放入Macrotask或者Microtask,promise属于Microrask。这篇文章,我们先忽略Macrotask。

3:异步的代码一定是要等到同步的代码执行完了才执行。也就是说,直到JS Stack为空,Microtask里面的代码才会被提到JS Stack,然后被执行。

4:new Promise()和.then()方法属于同步代码。

5:.then(resolveCallback, rejectCallback)里面的resolveCallback, rejectCallback的执行属于异步代码,会被放入Microtask。

6: resolve()被调用会起到2点作用:

1:Promise由pending状态变为resolved
2:遍历这个promise上所注册的所有的resolveCallback方法,依次加入Microtask。

7: .then()只是注册callback方法,并不会把callback方法加入Microtask(参考上面的第6点)。

好的,有了以上的7点前提知识,我们接下来看2个例子,运用以上的7点来分析promise的执行顺序。
第一个例子:

new Promise((resolve, reject)=> {  
    resolve(1);  
  Promise.resolve().then(()=>{  
        console.log(2);  
  })  
}).then((t)=>{console.log(t)});  
console.log(3);

以上代码的正确输出结果为:3,2,1
如果你的答案是错误的,就跟着我一步一步来分析为什么是3,2,1:

Step1:new Promise(...)
Screen Shot 2020-02-10 at 3.56.08 PM.png

运用上面的第4点知识,new Promise()是同步代码,所以会被立即执行。也就是会去执行它的executor function。我们把这个外层的promise叫做outerPromise。

Step 2: resolve(1)
Screen Shot 2020-02-10 at 4.03.51 PM.png

运用第6大点的第1小点知识,此时最外层的这个promise由pending状态变为resolved状态。但是,因为我们现在还没有执行到最外层的then()方法,所以此刻最外层的promise上并没有注册任何的callback方法,所以,也就无法把

(t)=>{console.log(t)}

这个callback放入Microtask里面。
这一步执行完:

JS Stack:  [outerPromise-executor-function]
Microtask: []

Step3:Promise.resolve().then(...)
Screen Shot 2020-02-10 at 4.09.06 PM.png
这里是直接创建了一个应是resolved状态的promise,我们把它叫做innerPromise。运用第4点知识,then()方法是被立即执行,再运用第6点知识,这一步代码执行之后,innerPromise的这个callback方法会被加入到Microtask。这块代码执行完之后,outerPromise-executor-function也就执行完了,所以这一步之后的状态是:

JS Stack:  []
Microtask: [innerPromise-callback]

Step4: .then((t)=>{console.log(t)})
终于执行到了outerPromise的then()方法,因为outerPromsie已经是resolved的了,所以这个callback方法会被立即加入MicroTask。所以,这步执行完之后,我们的执行栈的状态是:

JS Stack:  []
Microtask: [innerPromise-callback,outerPromise-callback]

Step5: console.log(3)
因为这行是同步代码,此刻JS Stack又是为空,所以这行代码会被立刻放入JS Stack且执行,所以我们得到结果:

打印结果:3

这一步执行完之后,我们的运行栈状态为:

JS Stack:  []
Microtask: [innerPromise-callback,outerPromise-callback]

Step6: 把innerPromise-callback从Microtask提到JS Stack且执行
因为此刻JS Stack为空,且安装先入先出的顺序,innerPromise-callback就被放入JS Stack且执行。之后,我们运行栈状态为:

JS Stack:  []
Microtask: [outerPromise-callback]
打印结果:3,2

Step6: 把outerPromise-callback从Microtask提到JS Stack且执行
类似地,outerPromise-callback被提入到JS Stack且执行。至此,我们的所有代码都执行完了,最终得到结果:

JS Stack:  []
Microtask: []
打印结果:3,2,1

以上就是,为什么打印结果为3,2,1的分析过程。

为了验证真的理解了整个机制,下面我们对以上代码做一点修改:

new Promise((resolve, reject)=>{  
    Promise.resolve().then(()=>{  
        resolve(1);  
        Promise.resolve().then(()=>{console.log(2)})  
    })  
}).then((value)=>{console.log(value)});  
console.log(3);

那这段代码的输出结果又是什么呢?


nanaistaken
583 声望43 粉丝