亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Javascript 承諾好奇心

Javascript 承諾好奇心

胡子哥哥 2022-12-09 15:18:03
當我調用這個 promise 時,輸出與函數調用的順序不匹配。The.then出現在 之前.catch,即使 promise with.then被調用之后。這是什么原因?const verifier = (a, b) =>  new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));verifier(3, 4)  .then((response) => console.log("response: ", response))  .catch((error) => console.log("error: ", error));verifier(5, 4)  .then((response) => console.log("response: ", response))  .catch((error) => console.log("error: ", error));輸出node promises.jsresponse: trueerror: false
查看完整描述

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 順序從一個級別遍歷到下一個級別,而不是同步的。


關于依賴此級別的調度詳細信息的一般建議

僅供參考,一般來說,我嘗試編寫不依賴于這種詳細時序知識的代碼。雖然它很好奇并且有時對理解很有用,但它是脆弱的代碼,因為對代碼進行看似無害的簡單更改可能會導致相對時序發生變化。因此,如果像這樣的兩條鏈之間的時序至關重要,那么我寧愿以一種強制按照我想要的方式進行時序的方式編寫代碼,而不是依賴于這種詳細的理解水平。


查看完整回答
反對 回復 2022-12-09
?
哆啦的時光機

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



查看完整回答
反對 回復 2022-12-09
  • 2 回答
  • 0 關注
  • 111 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號