2 回答

TA貢獻1799條經驗 獲得超9個贊
這是一個很酷的問題,需要深入探究。
當你這樣做時:
verifier(3,4).then(...)
返回一個新的承諾,在新拒絕的承諾可以運行后面的處理程序之前,需要另一個循環(huán)回到事件循環(huán).catch()。這個額外的循環(huán)給出了下一個序列:
verifier(5,4).then(...)
有機會.then()在上一行之前運行它的處理程序,因為在第一個處理程序進入隊列.catch()之前它已經在隊列中,并且項目以 FIFO 順序從隊列中運行。.catch()
請注意,如果您使用.then(f1, f2)form 代替.then().catch(),它會在您期望的時候運行,因為沒有額外的承諾,因此不涉及額外的滴答:
const verifier = (a, b) =>
new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));
verifier(3, 4)
.then((response) => console.log("response (3,4): ", response),
(error) => console.log("error (3,4): ", error)
);
verifier(5, 4)
.then((response) => console.log("response (5,4): ", response))
.catch((error) => console.log("error (5,4): ", error));
請注意,我還標記了所有消息,這樣您就可以看到verifier()
它們來自哪個調用,從而更容易閱讀輸出。
ES6 Spec on promise 回調排序和更詳細的解釋
.then()
ES6 規(guī)范告訴我們,promise“作業(yè)”(因為它調用 a或 的回調.catch()
)根據(jù)它們被插入作業(yè)隊列的時間以 FIFO 順序運行。它沒有具體命名 FIFO,但它指定新作業(yè)插入隊列末尾,作業(yè)從隊列開頭運行。這實現(xiàn)了 FIFO 排序。
PerformPromiseThen(執(zhí)行來自 的回調.then()
)將導致EnqueueJob,這是解決或拒絕處理程序被安排實際運行的方式。EnqueueJob 指定將掛起的作業(yè)添加到作業(yè)隊列的后面。然后NextJob操作從隊列的前面拉出項目。這確保了 Promise 作業(yè)隊列中服務作業(yè)的 FIFO 順序。
因此,在原始問題的示例中,我們獲得了verifier(3,4)
promise 的回調和按verifier(5,4)
運行順序插入作業(yè)隊列的 promise,因為這兩個原始 promise 都已完成。然后,當解釋器返回到事件循環(huán)時,它首先開始執(zhí)行verifier(3,4)
任務。該承諾被拒絕,并且在verifier(3,4).then(...)
. 因此,它所做的是拒絕verifier(3,4).then(...)
返回的承諾,并導致將verifier(3,4).then(...).catch(...)
處理程序插入到 jobQueue 中。
然后,它返回到事件循環(huán),它從 jobQueue 中提取的下一個作業(yè)就是作業(yè)verifier(5, 4)
。它有一個已解決的承諾和一個解決處理程序,因此它調用該處理程序。這會導致response (5,4):
顯示輸出。
然后,它返回到事件循環(huán),它從 jobQueue 中提取的下一個作業(yè)是verifier(3,4).then(...).catch(...)
它運行該作業(yè)的作業(yè),這會導致顯示error (3,4)
輸出。
這是因為.catch()
第一個鏈中的承諾級別在其鏈中比.then()
第二個鏈中的承諾級別更深,這導致了您報告的排序。而且,這是因為 promise 鏈是通過作業(yè)隊列以 FIFO 順序從一個級別遍歷到下一個級別,而不是同步的。
關于依賴此級別的調度詳細信息的一般建議
僅供參考,一般來說,我嘗試編寫不依賴于這種詳細時序知識的代碼。雖然它很好奇并且有時對理解很有用,但它是脆弱的代碼,因為對代碼進行看似無害的簡單更改可能會導致相對時序發(fā)生變化。因此,如果像這樣的兩條鏈之間的時序至關重要,那么我寧愿以一種強制按照我想要的方式進行時序的方式編寫代碼,而不是依賴于這種詳細的理解水平。

TA貢獻1779條經驗 獲得超6個贊
Promise.resolve()
.then(() => console.log('a1'))
.then(() => console.log('a2'))
.then(() => console.log('a3'))
Promise.resolve()
.then(() => console.log('b1'))
.then(() => console.log('b2'))
.then(() => console.log('b3'))
由于相同的原因,您將看到 a1、b1、a2、b2、a3、b3 而不是輸出 a1、a2、a3、b1、b2、b3 - 每個 then 都會返回一個 promise 并且它會進入事件循環(huán)的末尾隊列。所以我們可以看到這個“無極跑”。當有一些嵌套的承諾時也是如此。
添加回答
舉報