6

这篇文章动机是为了解释这个问题

往下阅读之前你需要知道,promise的resolve回调函数会被放在job queue中等待主任务执行完毕后等待执行(这也是文章提到的问题的解答)。可以参考这篇文章

代码一

new Promise((resolve, reject) => {
    resolve();  //将resolved回调函数(then的第一个参数)添加到queue队列
}).then(() => {
    console.log("promise1 resolved");
});

new Promise((resolve, reject) => {
    resolve();  //将resolved回调函数(then的第一个参数)添加到queue队列
}).then(() => {
    console.log("promise3 resoved");
});
console.log('main');

//result:
//main
//promise1 resolved
//promise3 resoved

这个结果很好理解,两个resolve()函数将两个回调函数依次添加到job queue队列,主任务队列执行完后,依次执行job queue中的任务。

代码二

在看代码前首先要理解promise then函数的返回值也是一个promise,而返回的promise的状态(pending,resolved,reject)在不同情况下会是不同的值,具体请参考MDN上的解释。为方便理解,请大家记住下面这段代码中的then函数的返回值均是处于resolved状态的promise。并请牢记一个promise如果是resolved状态则它会将其then回调函数作为一个任务添加到job queue。为方便解释,我会在代码中将每个then函数标记为一个任务,希望大家能对照着看。OK,让我们来看代码

new Promise((resolve, reject) => {
    resolve();  //resolve_1
}).then(() => {  // then_task_1
    console.log("promise1 resolved");
}).then(() => {  // then_task_2
    console.log("promise2 resolved");
}).then(() => {  // then_task_3
    console.log("promise3 resolved");
});

new Promise((resolve, reject) => {
    resolve();  //resolve_2
}).then(() => {  // then_task_x
    console.log("promisex resolved");
}).then(() => {  // then_task_y
    console.log("promisey resolved");
}).then(() => {  // then_task_z
    console.log("promisez resolved");
});

console.log('main');

//result:
//main
//promise1 resolved
//promisex resolved
//promise2 resolved
//promisey resolved
//promise3 resolved
//promisez resolved

1,首先resolve_1将then_task_1添加到job queue,然后resolve2将then_task_x添加到job queue。然后执行到console.log('main')。
主任务队列中的任务执行完成,主任务队列空(是的,这时job queue中只有then_task_1和then_task_x)。
2,开始执行job queue中的任务:执行then_task_1,打印promise1,这时返一个resolved promise,这个promise的then是then_task_2,js将then_task_2添加到then_task_x后;执行then_task_x,打印promisx,同理将then_task_y添加到then_task_2后。依次类推,我们就看到了代码结果这样的打印顺序。

代码三

new Promise((resolve, reject) => {
    resolve(Promise.resolve().then(() => { //then_task_innner
        console.log('inner promise resolved') 
    })); //外层resolve对应then_task1,内层resolve对应then_task_inner
}).then(() => { //then_task_1
    console.log("promise1 resolved");
});
new Promise((resolve, reject) => {
    resolve();  //resolve2
}).then(() => { //then_task_2
    console.log("promise2 resolved");
});
console.log('main');

//result:
//main
//inner promise resolved
//promise2 resolved
//promise1 resolved

这段代码执行到第一个resolve时发现其参数是一个resolved promise的then回调函数,这个参数是无法立即计算出值来的(因为这个then_task_innner被添加到job queue不会被立即执行)。所以这个resolve函数不会被立即执行。所以到这里then_task_innner被添加到job queue了,但是then_task_1并没有,因为其对应的promise还处于pending状态,没有被resolve。然后执行到resolve2,将then_task_2添加到job queue。然后执行console.log('main'),主任务队列完成。这时job queue中有then_task_inner和then_task_2。当执行完then_task_inner后,第一个resolve()会被添加到job queue,这时job queue中只有resolve()这个任务,这个resolve被执行。其对应的promise变为resolved状态,对应的then_task_1被添加到job queue中,然后被执行。因此我们看到屏幕上的打印结果是这样的。

代码四

有了代码三的铺垫,我们现在来看看下面这段代码。

new Promise((resolve, reject) => {
    resolve(Promise.resolve());  //为方便解释,我们将外层的resolve叫做 outer_resolve;内层的resolve叫做inner_resolve
}).then(() => {  //promise1_task
    console.log("promise1 resolved");
});
new Promise((resolve, reject) => {
    resolve();  //resolve2 对应 promise2_task
}).then(() => {  //promise2_task
    console.log("promise2 resolved");
}).then(() => {  //promise3_task
    console.log("promise3 resolved");
});
console.log('main');

//result:
//main
//promise2 resolved
//promise3 resolved
//promise1 resolved

放这段代码是为了过渡,方便解释下面的问题。
这段代码对比代码三inner_resolve没有了.then();不过并不是没有了,我们可以理解为inner_resolve对应的promise的then函数是null。
程序首先运行到第一个resolve,发现无法立即获得参数值,对应的promise无法改变状态,任然是pendding,所以对应的promise1_task不会被添加到job queue。然而inner_resolve被执行了,其对应的then函数(null)被添加到job queue。接下来第二个resolve被执行,对应的promise2_task被添加到job queue。之后主任务执行完成,开始执行job queue中的任务。对一个任务是null,执行完后因为第一个resolve的参数有了,所以这个resolve函数被添加到job queue中;接下来是执行promise2_task,打印promise2 并将promise3_task添加到job queue。然后执行第一个resolve函数,其对应的promise1_task被添加到job queue。接下来是执行promise3_task,然后promise1_task。
如果我们将resolve(Promise.resolve())换成resolve()。就会看到打印结果顺序是promise1,promise2,promise3。

回到最初的问题

new Promise((resolve, reject) => {
    console.log("async1 start");
    console.log("async2");
    resolve(Promise.resolve());  //这里的Promise.resolve会添加一个null任务到job queue,外层resolve对应async1_end_task
}).then(() => {   //async1_end_task
    console.log("async1 end");
});

new Promise(function(resolve) {
    console.log("promise1");
    resolve();  //对应promise2_task
}).then(function() {  //promise2_task
    console.log("promise2");
}).then(function() { //promise3_task
    console.log("promise3");
}).then(function() { //promise4_task
    console.log("promise4");
});

//result:
//async1 start
//async2
//promise1
//promise2
//promise3
//async1 end
//promise4

这里我们对async1 start,async2,promise1的打印顺序不解释,这时在主任务中执行的,按主任务执行顺序打印。
romise2,promise3,async1 end,promise4的打印顺序解释同代码四


黑将军
168 声望8 粉丝