2015-11-28 92 views
4

我有一些Javascript代碼做一些異步的東西一些同步後處理,然後再次異步的東西(XHR - >解析XHR - >新的基於第一個XHR)。我不明白的錯誤處理完成:錯誤處理在Javascript承諾

/* API */ 
function getFile(name) { 
    return $.ajax({ 
     url: name + ".json" 
    }).then(function(data) { 
     return data.id 
    }, handleError) 
} 

function handleError(errorObj) { 
    if (errorObj.status) { 
     return errorObj.status 
    } else { 
     return errorObj 
    } 
} 

function myApiCall() { 
    return getFile(1) 
     .then(getFile, handleError) 
     .then(getFile, handleError) 
     .then(getFile, handleError) 
     .then(getFile, handleError); 
} 


/* caller */ 

function failFunction(status) { 
    console.log("fail: ") 
    console.log(status) 
} 

myApiCall().then(function(id) { 
     console.log(id) 
    }, failFunction) 

1.json看起來像這樣

{ 
    "id": "2" 
} 

只是引用下一個文件,其他的人是等價的。

直到這裏一切都很好(即使我不知道這是做錯誤處理的最佳方式)。如果所有文件都存在,則調用者的成功函數被調用,否則爲錯誤函數。

但在我同步代碼有一些錯誤時,寄託都打破

function getFile(name) { 
    return $.ajax({ 
     url: name + ".json" 
    }).then(function(data) { 
     throw new Error(42) //  <--------- 
    }, handleError) 
} 

現在,我得到一個控制檯輸出

Error: 42 

沒有進一步的處理,主叫方不知情。

我想類似的東西

function getFile(name) { 
    return $.ajax({ 
     url: name + ".json" 
    }).then(function(data) { 
     throw new Error(42) 
    }, handleError) 
    .catch(handleError) 
} 

但是,這並不做任何事情更好。大多數我得到一個TypeError: $.ajax(...).then(...).catch is not a function

在這種情況下錯誤處理如何解決正確?

+2

如果您從捕獲或錯誤處理程序返回值,則錯誤不會傳播 - 如果您希望它傳播,則拋出錯誤或返回Promise.reject。 jquery函數可能會搞砸承諾鏈這一事實並不令人意外,jquery承諾不是(至少在v3之前)真正符合Promise/A +標準 –

回答

7

因爲你的每一個階段處理錯誤,而不是傳播他們,那麼你將最終獲得您所遇到的問題

編輯:

上述說法是錯誤的,我沒有」牛逼實現jQuery的承諾如何破的,當我寫的 - 看到的一個代碼塊之間(無極/ A +)和第二差(用手指jQuery的承諾交叉背後它的背部)

相反,你可以做一些事情喜歡:

function getFile(name) { 
    // wrap jquery "promise" in real Promise 
    // you'll need a Promise polyfill for Internet Explorer to use this method 
    return new Promise(function(resolve, reject) { 
    $.ajax({ 
     url: name + ".json?" + Math.random() 
    }).then(function(data) { 
     resolve(data.id); 
    }, function(err) { 
     reject(err); 
    }); 
    }); 
} 

function handleError(errorObj) { 
    //console.log(errorObj) 
    if (errorObj.status) { 
    throw errorObj.status; 
    } else { 
    throw errorObj; 
    } 
} 

function myApiCall() { 
    return getFile(1) 
    .then(getFile) 
    .then(getFile) 
    .then(getFile) 
    .then(getFile) 
    .catch(handleError); 
} 

function failFunction(status) { 
    console.log("fail: ") 
    console.log(status) 
} 

myApiCall().then(function(id) { 
    console.log(id); 
}) 
.catch(failFunction); 

當使用jQuery,它的諾言就像你與你的手指穿過的承諾你的背部

function getFile(name) { 
    return $.ajax({ 
     url: name + ".json" 
    }).then(function(data) { 
     return data.id; 
    }); 
} 
function handleError(errorObj) { 
    if (errorObj.status) { 
     return errorObj.status; // return in jquery! 
    } else { 
     return errorObj; 
    } 
} 
function myApiCall() { 
    return getFile(1) 
     .then(getFile) 
     .then(getFile) 
     .then(getFile) 
     .then(getFile) 
     .fail(handleError); // like jquery promises in general, use fail instead of the compliant catch 
} 
/* caller */ 
function failFunction(status) { 
    console.log("fail: "); 
    console.log(status); 
} 
myApiCall().then(function(id) { 
    console.log(id); 
}) 
.fail(failFunction); 
+0

你試過嗎?粘貼你的代碼對我來說有效果,即錯誤不會被翻譯成狀態碼並拋出新的錯誤(42)仍然會導致未捕獲的異常... – mibutec

+0

'你試過了嗎?' - 儘可能多地訪問你的服務器和文件! '錯誤沒有被轉換成statuscode' ... errorObj有一個'.status' - console.log它找出...就未捕獲的異常去,你使用jquery,祝你好運像承諾應該 –

+0

我剛剛測試了jQuery版本(第一版**不會工作,如果你使用後面的承諾** jquery交叉手指),它工作正常使用.fail等 –

0

各位背後使用jQuery當厭倦了承諾。承諾真的很酷; jQuery承諾很糟糕。這裏有一些基於Jaromandas的更多示例代碼可供任何人使用。

/* API */ 
function getFileWithError(name) { 
    return getFile(name, true) 
} 

function getFile(name, doThrow) { 
    if (name == null) { 
    console.log("handled null as return from chain before") 
    name = 2 
    } 
    return wrapJquery(
    $.ajax({ 
     url: name + ".json?" + Math.random() 
    }) 
).then(function(data) { 
    if (data.id == 2) { 
     return null 
    } 
    if (doThrow) { 
     throw data.id 
    } 
    return data.id 
    }); 
} 

function wrapJquery(crossingFingersPromise) { 
    return new Promise(function(resolve, reject) { 
     crossingFingersPromise 
     .then(function(data) { 
      resolve(data); 
     }, function(err) { 
      reject(err); 
     }); 
    }) 
} 

function handleError(errorObj) { 
    if (errorObj.status) { 
     throw errorObj.status; // return in jquery! 
    } else { 
     throw errorObj; 
    } 
} 

function myApiCall() { 
    return getFile(1) 
     .then(getFile) 
     .then(getFileWithError) 
     .then(getFile, function(error) { 
      console.log("recovering from error") 
      return getFile(error) 
     }) 
     .then(getFile) 
     .catch(handleError) 
} 
/* caller */ 
function failFunction(status) { 
    console.log("fail: "); 
    console.log(status); 
} 
myApiCall().then(function(id) { 
    console.log(id); 
}) 
.catch(failFunction);