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

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

被束縛的承諾不會被拒絕

被束縛的承諾不會被拒絕

溫溫醬 2019-06-20 15:52:13
被束縛的承諾不會被拒絕我很難理解為什么拒絕不能通過承諾鏈傳遞,我希望有人能幫助我理解其中的原因。對我來說,將功能附加到一系列的承諾中意味著我依賴于最初的承諾來實現它的意圖。很難解釋,所以讓我先給出一個問題的代碼示例。(注意:此示例使用Node和延遲節點模塊。我用Dojo 1.8.3進行了測試,得到了相同的結果)var d = require("deferred");var d1 = d();var promise1 = d1.promise.then(     function(wins) { console.log('promise1 resolved'); return wins;},     function(err) { console.log('promise1 rejected'); return err;});var promise2 = promise1.then(     function(wins) { console.log('promise2 resolved'); return wins;},     function(err) { console.log('promise2 rejected'); return err;});var promise3 = promise2.then(     function(wins) { console.log('promise3 resolved'); return wins;},     function(err) { console.log('promise3 rejected'); return err;});d1.reject(new Error());運行此操作的結果是以下輸出:promise1 rejected promise2 resolved promise3 resolved好吧,對我來說,這個結果沒有意義。通過附加到這個承諾鏈上,每個承諾鏈都意味著它將依賴于D1的成功解決,并將結果傳遞到該鏈中。如果承諾1中的承諾沒有接收WINS值,而是在其錯誤處理程序中獲得錯誤值,那么如何使鏈中的下一個承諾調用其成功函數?它不可能將有意義的值傳遞給下一個承諾,因為它本身沒有得到一個值。另一種我可以描述的想法是:有三個人,約翰,金格和鮑勃。約翰擁有一家小玩具店。姜走進他的店里,要了一袋五顏六色的小玩意兒。他沒有庫存,所以他向他的分銷商發出了一份請求,要求把它們運給他。同時,他給了金格一次改天的機會,說他欠她一袋小工具。Bob發現Ginger正在獲取這些小部件,并要求在完成這些小部件后獲得藍色小部件。她同意了,并給了他一張紙條,說她會的。現在,John的分銷商在他們的產品中找不到任何小部件,制造商也不再生產這些小部件,所以他們通知John,John反過來告訴Ginger她無法獲得這些小部件。鮑勃怎么能從金格那里得到一個藍色的小部件,而她卻沒有得到任何東西呢?我對這個問題的第三個更現實的觀點是這一點。假設我有兩個要更新到數據庫的值。一個依賴于另一個的id,但是在我已經將它插入數據庫并獲得結果之前,我無法獲得id。除此之外,第一個INSERT依賴于來自數據庫的查詢。數據庫調用返回承諾,用于將兩個調用鏈接到一個序列中。現在,在這種情況下,如果db.query失敗,它將調用第一個查詢的err函數。但是,它會把下一個承諾的成功函數稱為“成功函數”。雖然這個承諾是期望第一個值的結果,但是它將從它的錯誤處理程序函數中得到錯誤消息。所以,我的問題是,如果我必須測試我的成功函數中的錯誤,為什么我會有一個錯誤處理函數呢?很抱歉這么長時間。我只是不知道怎么用另一種方式來解釋
查看完整描述

3 回答

?
智慧大石

TA貢獻1946條經驗 獲得超3個贊

首先正如評論者所指出的,在使用延遲庫時,您的第一個示例肯定會產生您期望的結果:

promise1 rejected
promise2 rejected
promise3 rejected

其次,即使它會產生您建議的輸出,它也不會影響第二個片段的執行流,這有點不同,更像是:

promise.then(function(first_value) {
    console.log('promise1 resolved');
    var promise = db.put(first_value);
    promise.then(function (second_value) {
         console.log('promise2 resolved');
         var promise = db.put(second_value);
         promise.then(
             function (wins) { console.log('promise3 resolved'); },
             function (err) { console.log('promise3 rejected'); return err; });
    }, function (err) { console.log('promise2 rejected'); return err;});}, function (err) { console.log('promise1 rejected'); return err});

而且,如果第一次承諾被拒絕,就會產生這樣的結果:

promise1 rejected

然而(進入最有趣的部分)即使延遲的庫肯定會返回3 x rejected,大多數其他承諾庫將返回。1 x rejected, 2 x resolved(這會導致假設您通過使用其他承諾庫來獲得這些結果)。

另外,令人困惑的是,其他庫的行為更正確。讓我解釋一下。

在同步世界中,“拒絕承諾”的對應詞是throw..所以在語義上,異步deferred.reject(new Error())同步等于throw new Error()..在您的示例中,您沒有在同步回調中拋出錯誤,您只是返回它們,因此切換到成功流,錯誤是成功的值。為了確保拒絕得到進一步通過,您需要重新拋出錯誤:

function (err) { console.log('promise1 rejected'); throw err; });

所以現在的問題是,為什么延遲庫將返回的錯誤作為拒絕?

原因是,在推遲的情況下,拒絕的工作方式有點不同。在延遲庫中,規則是:承諾在被錯誤實例解析后被拒絕所以即使你這么做deferred.resolve(new Error())它將充當deferred.reject(new Error()),如果你想做deferred.reject(notAnError)它會拋出一個異常,也就是說,只有在錯誤的情況下才能拒絕承諾。這說明了為什么從then回調拒絕承諾。

遞延邏輯背后有一些合理的推理,但它仍與如何做到這一點相去甚遠。throw在JavaScript中工作,并且由于此行為計劃更改版本V0.7的延遲。

摘要:

為了避免混亂和意想不到的結果,只需遵循良好的實踐規則:

  1. 始終用錯誤實例拒絕您的承諾(遵循同步世界的規則,其中拋出不是錯誤的值被認為是錯誤的做法)。
  2. 從同步回調中拒絕

    投擲

    錯誤(返回錯誤不能保證拒絕)。

遵循以上所述,您將在延遲庫和其他流行的承諾庫中獲得一致和預期的結果。


查看完整回答
反對 回復 2019-06-20
  • 3 回答
  • 0 關注
  • 558 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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