簡體   English   中英

鏈接Javascript承諾

[英]Chaining Javascript promises

我試圖從MDN文檔中了解Promises。 第一個示例演示了thencatch方法:

// We define what to do when the promise is resolved/fulfilled with the then() call,
// and the catch() method defines what to do if the promise is rejected.
p1.then(
    // Log the fulfillment value
    function(val) {
        log.insertAdjacentHTML('beforeend', val +
            ') Promise fulfilled (<small>Async code terminated</small>)<br/>');
    })
.catch(
    // Log the rejection reason
    function(reason) {
        console.log('Handle rejected promise ('+reason+') here.');
    });

文檔聲明then方法返回一個新的promise,所以不要將上面的代碼等同於

var p2 = p1.then(
    // Log the fulfillment value
    function(val) {
        log.insertAdjacentHTML('beforeend', val +
            ') Promise fulfilled (<small>Async code terminated</small>)<br/>');
    });
p2.catch(
    // Log the rejection reason
    function(reason) {
        console.log('Handle rejected promise ('+reason+') here.');
    });

如果是這樣,那么這是不是意味着只有當從p1.then返回的p1.then而不是promise p1被拒絕時才會調用catch回調? 我不是必須這樣做的:

p1.then( /* etc. */ );
// and for rejected resolutions
p1.catch( /* etc. */ );

抓住承諾p1的拒絕而不是將catch鏈接到then

起初,我認為從p1.then返回的p1.thenp1相同,就像jQuery如何處理它的大部分API一樣。 但以下清楚地表明這兩個承諾是不同的。

var p1 = new Promise(function(resolve, reject) { 
  resolve("Success!");
});

console.log(p1);
// Promise { <state>: "fulfilled", <value>: "Success!" }

var p2 = p1.then(function(value) {
  console.log(value);
});
// Success!

console.log(p2); 
// Promise { <state>: "fulfilled", <value>: undefined }

另外,我在JSFiddle中玩了三種方法:

  1. p1.then(onFulfilled).catch(onRejected);
  2. p1.then(onFulfilled); p1.catch(onRejected);
  3. p1.then(onFulfilled, onRejected);

這三個都有效。 我能理解后兩者。 我的問題的要點是,為什么第一種方法也有效?

首先,關於承諾相關部分如何運作的一些背景知識:

p1.then(...)確實返回一個鏈接到前一個的新承諾。 所以, p1.then(...).then(...)只有在第一個完成后才會執行第二個.then()處理程序。 並且,如果第一個.then()處理程序返回一個未實現的promise,那么它將在解析第二個promise並調用第二個.then()處理程序之前等待該返回的promise解析。

其次,當一個promise鏈拒絕鏈中的任何地方時,它會立即跳過鏈(跳過任何已完成的處理程序),直到它到達第一個拒絕處理程序(無論是來自第二個參數的.catch().then() )。 這是承諾拒絕的一個非常重要的部分,因為這意味着您不必在承諾鏈的每個級別捕獲拒絕。 您可以在鏈的末尾放置一個.catch() ,並且鏈中任何位置發生的任何拒絕都將直接轉到該.catch()

另外,值得理解的是.catch(fn)只是.catch(fn) .then(null, fn)的快捷方式。 它沒有區別。

此外,記住,(就像.then().catch()也將返回一個新的承諾。 如果你的.catch()處理程序本身不拋出或返回被拒絕的promise,那么拒絕將被視為“已處理”,並且返回的promise將被解析,允許鏈從那里繼續。 這允許您處理錯誤,然后有意識地決定您是否希望鏈繼續正常的履行邏輯或保持拒絕。

現在,針對您的具體問題......

如果是這樣,那么這是不是意味着只有當從p1.then返回的promise而不是promise p1被拒絕時才會調用catch回調? 我不是必須這樣做的:

拒絕拒絕在鏈中傳播到下一個拒絕處理程序,跳過所有解析處理程序。 因此,它會在您的示例中跳過鏈接到下一個.catch()

這是使用錯誤處理錯誤的事情之一。 您可以將.catch()放在鏈的末尾,它將從鏈中的任何位置捕獲錯誤。

有時候有理由在鏈的中間攔截錯誤(如果你想在錯誤上分支和更改邏輯,然后繼續使用其他代碼),或者如果你想“處理”錯誤並繼續進行。 但是,如果您的鏈是全部或全部,那么您可以在鏈的末尾放置一個.catch()來捕獲所有錯誤。

它類似於同步代碼中的try / catch塊。 在鏈的末尾放置一個.catch()就像在一堆同步代碼的最高級別放置一個try / catch塊。 它將捕獲代碼中的任何位置的異常。

這三個都有效。 我能理解后兩者。 我的問題的要點是,為什么第一種方法也有效?

這三個都差不多。 2和3是相同的。 實際上, .catch(fn)只不過是.catch(fn) .then(null, fn)的快捷方式。

選項1略有不同,因為如果onFulfilled處理程序拋出或返回被拒絕的promise,則會.catch()處理程序。 在另外兩個選項中,情況並非如此。 除了那一個差異,它將工作相同(如你所觀察到的)。

選項1有效,因為拒絕在鏈中傳播。 因此,如果p1拒絕或者onFulfilled處理程序返回被拒絕的promise或throws,則將.catch()處理程序。

代碼不應該是等同的

他們是。

如果是這樣,那么這是不是意味着只有當從p1.then返回的p1.then而不是promise p1被拒絕時才會調用catch回調?

對,就是這樣。

但是當p1拒絕時, p2也會這樣做,因為你沒有將onRejected處理程序傳遞給可以攔截它的onRejected .then()調用。 拒絕只是沿着鏈傳播。

我使用這三種方法在JSFiddle中玩游戲。 這三個都有效。

他們這樣做,但他們不這樣做。

 p1.then(onFulfilled, onRejected); 

這是你通常想做的事情。

 p1.then(onFulfilled); p1.catch(onRejected); 

最終會有兩個不同的承諾,一個將使用onFulfilled結果解決或被拒絕,另一個將使用onRejected結果實現或解決。

 p1.then(onFulfilled).catch(onRejected); 

那是一個與第一個不同的野獸,看什么時候。然后(成功,失敗)被認為是承諾的反模式?

這個:

var p2 = p1.then()
p2.catch()

與此相同:

p1.then().catch()

你也可以這樣做:

p1
 .then(response => response.body)
 .then(body => JSON.parse(body))
 .then(data => console.log(data))
 .catch(e => console.log('something somewhere failed'))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM