两道Promise案例

721 阅读3分钟

一说起Promise执行顺序,你会想到啥?

“不就是老掉牙的宏任务,微任务嘛,事件循环嘛”

先来两道题,看能不能答对吧,如果你懒得复制到浏览器中运行,就跳到文章最后看答案吧👀

// 案例一
new Promise((resolve, reject)=> {  
  resolve(1);  
  Promise.resolve().then(()=>{  
        console.log(2);  
  })  
}).then((t)=>{console.log(t)});  
console.log(3);
// 案例二
new Promise((resolve, reject)=>{  
    Promise.resolve().then(()=>{  
        resolve(1);  
        Promise.resolve().then(()=>{console.log(2)})  
    })  
}).then((value)=>{console.log(value)});  
console.log(3);

怎么样,和你预想的一致嘛,如果一致,哪你可以走了,这个文章不适合你!

如果百思不得其解,那就继续往下看

执行顺序

先说一个观点

.then()是同步方法,里面的callback才是异步的

案例一执行顺序

1、new Promise(...)

new Promise是同步代码,首先执行的就是里面的回调

2、resolve(1)

此时最外层的Promise状态由pedding状态变为resolve

注意,由于现在还没有执行到最外层的then(),所以最外层的Promise没有注册任何callback,因此(t) => console.log(t)不会放到Microtask

3、Promise.resolve().then(...)

.then()会把里面的callback放入Microtask中,看看现在的执行栈状态

JS Stack: []
Microtask: [() => console.log(2)]

4、.then((t)=>{console.log(t)})

终于执行到最外层Promise的then方法了,此时的状态已经是resolve了,因此then里面的回掉要压入到Microtask中,此时的执行栈状态

JS Stack: []
Microtask: [() => console.log(2), (1) => console.log(1)]

5、console.log(3)

这肯定是同步了,此时JS Stack为空,因此会立即压入栈中执行,打印3

此时的执行栈状态

JS Stack: []
Microtask: [() => console.log(2), (1) => console.log(1)]

后面就是事件循环了,()=> console.log(2)压入JS Stack中并执行,执行完后又将() => conosle.log(1)压入JS Stack中并执行

所以案例一 打印 3 2 1

案例二执行顺序

1、new Promise(...)

image.png 不用说,同步执行,直接看里面的回调

2、Promise.resolve().then(...)

image.png .then是同步的,但里面的回调是异步的,因此回调进入Microtask中,此时的执行栈状态

JS Stack: []
Microtask: [ () => {resolve(1); Promise.resolve().then(....)} ]

3、.then(...)

image.png 执行到最外层Promisethen方法了,将回调压入Microtask中,此时的执行栈状态

JS Stack: []
Microtask: [ () => {resolve(1); Promise.resolve().then(....)}, (value) => console.log(value) ]

此时的微任务队列里面排队了两个任务,第一个是第二层Promise.then回调,第二个是第一层Promise.then回调

4、console.log(3)

image.png

同步,立即执行,打印 3,此时的执行栈状态

JS Stack: []
Microtask: [() => {resolve(1); Promise.resolve().then(....)}, (value) => console.log(value)]

5、将第二层的Promise-callback从Micotask中提升到JS Stack中

此时的执行栈状态

JS Stack: [() => {resolve(1); Promise.resolve().then(() => console.log(2))}]
Microtask: [(value) => console.log(value)]]

执行到resolve(1)时,第一层的Promise状态由pedding转为resolve

紧接着,执行Promise.resolve().then(() => console.log(2)},又将then里面的回调压入Microtask

JS Stack: []
Microtask: [ (1) => console.log(1), () => console.log(2) ]

6、将第一层的Promise-callback从Micotask中提升到JS Stack中

此时的执行栈状态

JS Stack: [ (1) => console.log(1) ]
Microtask: [ () => console.log(2) ]

执行后打印 1

7、将第三层的Promise-callback从Micotask中提升到JS Stack中

此时执行栈状态

JS Stack: [ () => console.log(2) ]
Microtask: []

执行后打印 2

综上,案例二打印结果为 3 1 2

答案

案例一打印:3 2 1

案例二打印:3 1 2

参考

JS-Promise的执行顺序