2017-01-24 23 views
0

我想要建立一個簡單的CRUD應用程序。用戶有個人資料頁面,可以填寫有關自己的字段並保存。我的問題是:承諾,不火「然後」如果錯誤發生

我使用HTTP請求愛可信(在終極版應用程序):

export const createCard = (data) => (dispatch) => 
    axios.post('/api/cards', data) 
     .then(
      response => dispatch({ 
       type: actions.CREATE_CARD_SUCCESS, 
       card: response.data 
      }) 
      error => dispatch({ 
       type: actions.CREATE_CARD_FAILURE, 
       message: error.message 
      }) 
     ) 
     .then(() => /* do something here, if no error occur */); 

,並要求已成功完成後,我想要做的東西,然後方法。但它觸發始終,即使錯誤有發生

這可以這樣實現:

export const createCard = (data) => (dispatch) => 
    axios.post('/api/cards', data) 
     .then(
      response => { 
       dispatch({ 
        type: actions.CREATE_CARD_SUCCESS, 
        card: response.data 
       }); 
      }, 
      error => { 
       dispatch({ 
        type: actions.CREATE_CARD_FAILURE, 
        message: error.message 
       }); 
       return error; 
      } 
     ) 
     .then(error => { 
      if (!error) { 
       /* do something here, if no error occur */ 
      } 
     }); 

但實在是太多了樣板。

在這種情況下,Jquery.ajax方便。

$.ajax() 
    .done() 
    .fail() 
    .always() 
    .then(() => { /** this callback will be fired if no error occur **/}) 

如何在axios或fetch api中模擬此行爲?

回答

1

看來,你有一個承諾,拒絕處理程序處理該拒絕時,不慎從拒絕回到解決,原來的承諾因此即使出現錯誤,您的以下.then()處理程序也會被調用。

當你創建或者.catch()或與第二回調.then()這樣一個承諾的錯誤處理:

p.then(result => { 
    // do something with result here 
}, err => { 
    console.err(err); 
}).then(result => { 
    // this will always get fired because you "ate" the error in the previous catch handler 
}); 

而且,你處理錯誤,而不重新拋出或不返回拒絕承諾,那麼承諾的基礎設施認爲你已經「處理」了錯誤,並且父母的承諾得到了解決(不再被拒絕)。因此,即使在鏈中早期發生錯誤,任何以下.then()處理程序都會被調用。

如果您想對錯誤進行操作(如記錄日誌或執行其他邏輯),但您希望承諾保持拒絕狀態,則必須重新引發錯誤或返回拒絕的承諾。這是保持連鎖被拒絕的唯一途徑。


雖然在你的問題的代碼似乎缺少一個逗號,它看起來像這應該是第二個參數爲.then()處理器。當承諾被拒絕因此將被調用:

 error => { 
      dispatch({ 
       type: actions.CREATE_CARD_FAILURE, 
       message: error.message 
      }); 
      return error; 
     } 

既然你只是做一個正常的return error,這將改變承諾得到解決(不再拒絕),因此以下.then()處理程序被調用。

要信守承諾拒絕,你可以重新拋出錯誤(與ES6標準的兼容的承諾),或者你可以返回一個拒絕承諾(帶有jQuery的.then()處理或ES6標準的兼容承諾):

 error => { 
      dispatch({ 
       type: actions.CREATE_CARD_FAILURE, 
       message: error.message 
      }); 
      // keep the promise rejected 
      return Promise.reject(error); 
     } 

注意:這與try/catch如何用於常規同步代碼非常類似。當您執行catch()時,除非您重新拋出它,否則將處理該異常並且不會傳播。承諾處理程序也一樣。

+0

好吧,正如我所看到的,沒有辦法讓像jquery中的邏輯。我所能做的就是拋出一個錯誤。謝謝你們兩位的回答<3 –

+0

@SmikeNelipov - 你是什麼意思「讓邏輯像jQuery」? – jfriend00

+0

jquery not fire .then after .fail '$ .ajax(... options).done()。fail()。then(/ *如果.fail回調捕獲錯誤,則不會觸發此回調* /) ' –

1

如果您在回調中省略了錯誤處理程序then,則任何錯誤都將傳播到下一個回調(確實有一個回調)(如果有的話)。 catch塊添加到您的鏈的末端,爲整個供應鏈進行錯誤處理:

axios.post('/api/cards', data) 
    .then(response => { 
     dispatch({ 
      type: actions.CREATE_CARD_SUCCESS, 
      card: response.data 
     }); 
    }).then(() => { 
     // this block won't be executed if there is a post error 
    }).catch(error => { 
     // handle post error 
     dispatch({ 
      type: actions.CREATE_CARD_FAILURE, 
      message: error.message 
     }); 
     // if we wished to propagate the error to the caller, skipping 
     // subsequent then blocks, we could re-raise it here by throwing it: 
     //  throw error; 
    }).then(() => { 
     // this block will be executed after the catch handler unless 
     // it raises another error by throwing an exception 
    }); 
+0

但如果我需要在一個組件然後觸發? 我有兩個頁面:1)項目列表,2)項目卡從該列表中。 用戶可以從列表和卡中刪除此項。當用戶從列表中刪除項目時,我只是想從列表中刪除它。但是,如果發生在卡片中,我想在成功後訪問/列出頁面。如果出現錯誤,我想保留在此頁面上並向用戶顯示錯誤。 在這種情況下我該怎麼辦? –

+0

如果你想吞下錯誤,把catch塊放到想要執行的'then'塊之前。接下來的'then'將在catch處理程序之後執行。 – teppic

+0

爲了清晰起見,我在答案中添加了一些評論。 – teppic