理解promise--一個問題引發的思考

這篇文章動機是爲了解釋這個問題

往下閱讀之前你需要知道,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的打印順序解釋同代碼四

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章