2 回答

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

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 并且它會進入事件循環的末尾隊列。所以我們可以看到這個“無極跑”。當有一些嵌套的承諾時也是如此。
添加回答
舉報