2017-03-15 104 views
0

我有一個承諾,可以解決或拒絕。我想在這些情況下做一些具體的事情,然後繼續解決諾言鏈(基本上我想「抓住」被拒絕的諾言,做點什麼,然後繼續解決)。延遲jQuery繼續解決失敗處理程序後

這裏有一個功能性片段,顯示我運行到這個問題:

var def = $.Deferred(); 
 
def.then(
 
    function() { 
 
    console.log('first success handler'); 
 
    }, 
 
    function() { 
 
    console.log('first fail handler'); 
 
    return $.Deferred().resolve(); 
 
    } 
 
); 
 
def.then(
 
    function() { 
 
    console.log('second success handler'); 
 
    }, 
 
    function() { 
 
    console.log('second fail handler'); 
 
    } 
 
); 
 
def.done(function() { 
 
    console.log('done handler'); 
 
}); 
 

 
def.reject();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

預期結果:

first fail handler 
second success handler 
done handler 

當前的結果:

first fail handler 
second fail handler 

據jQuery的文檔:

在jQuery 1.8中,deferred.then()方法返回一個新的承諾 可以過濾狀態和的值通過 功能遞延[...]。這些過濾器函數可以返回一個新值,傳遞給promise的.done()或.fail()回調函數,或者它們可以返回另一個可觀察對象(Deferred,Promise等),其中 將通過其解析/拒絕狀態和價值承諾的 回調。

所以我不知道爲什麼這不起作用。我期望在第一個失敗處理程序中返回已解決的承諾,以允許承諾鏈的其餘部分繼續解析。

+0

這是一個已知的bug。請參閱: http://stackoverflow.com/questions/31962655/recovering-from-rejected-promises-in-js – baohouse

回答

3

模式...

var def = $.Deferred(); 
def.then(successHandler, errorHandler); 
def.then(successHandler, errorHandler); 
// etc. 

...形成兩個(或更多)分支,每個then()僅取決於def。每個分支擁有獨立的過濾能力,但沒有被利用。

即從非常不同...

var def = $.Deferred(); 
def.then(successHandler, errorHandler).then(successHandler, errorHandler); // etc. 

...其形成單鏈(沒有分支)。第一個then()依賴於def,而第二個then()依賴於第一個then()。這裏,第一個then()的過濾功率是,通過鏈接另一個then()(依此類推)被利用。

因此,你會在問題的代碼轉換爲第二模式獲得預期的輸出:

var def = $.Deferred(); 

def.then(function() { 
    console.log('first success handler'); 
}, function() { 
    console.log('first fail handler'); // (1) 
    return $.Deferred().resolve(); 
}).then(function() { 
    console.log('second success handler'); // (2) 
}, function() { 
    console.log('second fail handler'); 
}).done(function() { 
    console.log('done handler'); // (3) 
}); 

def.reject(); 

簡而言之,這就是承諾鏈接是怎麼一回事。

但是不要忘記完全分支。在某些情況下,這是至關重要的。例如,在this answer中,batchRequests()返回_p,其可以由呼叫者(這是一個分支)進一步鏈接,但也與_p.then(..., ...)形成其自己的專用分支。如果無法完全遵循它,請不要擔心 - 現在相當複雜 - 現在請相信我,分支是解決方案的重要組成部分。

0

你的代碼實際上在做的是排隊兩個處理程序(通過then函數)。當延期被拒絕時,它不能再被改變。

當延遲被拒絕時,第一個then處理程序觸發寫入您的第一個控制檯消息。

return $.Deferred().resolve();將創建一個新的解析延遲,但它不會「返回」到您的第二個then,因爲該處理程序已經綁定到第一個延遲實例。

因此,你的第二個then處理程序現在會觸發failFilter(當Deferred被拒絕時的處理程序)。

您可以採取的一種方法是在拒絕(或解決)您的延期時傳遞一個值。然後,您可以接收響應,並採取補救措施如這(有點做作)樣品中:

<!DOCTYPE html> 
 
<html lang="en"> 
 
<head> 
 
    <meta charset="utf-8"> 
 
    <meta name="viewport" content="width=device-width, initial-scale=1"> 
 
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
</head> 
 
<body> 
 

 
<div id="test"></div> 
 

 
<script> 
 
    var def = $.Deferred(); 
 
    def.then(
 
      function() { 
 
       console.log('first success handler'); 
 
      }, 
 
      function (response) { 
 
       console.log('first fail handler'); 
 
       console.log(response); 
 
      } 
 
    ); 
 
    def.then(
 
      function() { 
 
       console.log('second success handler'); 
 
      }, 
 
      function (response) { 
 
       if (response === 999) { 
 
        // do something to recover from earlier reject 
 
        console.log('recovery action initiated'); 
 
       } else { 
 
        console.log('second fail handler'); 
 
       } 
 
      } 
 
    ); 
 
    def.done(function() { 
 
     console.log('done handler'); 
 
    }); 
 

 
    def.reject(999); 
 
</script> 
 

 
</body> 
 
</html>

我知道沒辦法兩個then處理程序之間插話,他們只不過是兩種排隊處理程序到相同的延遲。

+0

正確的,我明白你在做什麼,但文件非常清楚地說成功/失敗的過濾器_「,他們可以返回另一個可觀察對象(Deferred,Promise等),它將解析/拒絕狀態和值傳遞給promise的回調函數。所以我想知道的是爲什麼代碼不像文檔所說的那樣行事。 –

+0

請提供一個鏈接,指出您獲取該信息的位置。 – rasmeister

1

的文檔的重要組成部分,是

deferred.then()方法返回一個新的承諾

但是你被扔掉的是返回值,並沒有調用下.then(…)原始def

你將要使用

var p = $.Deferred().reject().promise(); 

p.then(function() { 
    console.log('first success handler'); 
}, function() { 
    console.log('first fail handler'); 
    return $.Deferred().resolve(); 
}).then(function() { 
//^^^^^ chain directly on the result 
    console.log('second success handler'); 
}, function() { 
    console.log('second fail handler'); 
}).then(function() { 
//^^^^^ 
    console.log('done handler'); 
});