[英]How to handle failed ajax request with promise
我正在這樣發出多個ajax請求
imgPromises = []; imgPromise1 = $.ajax({ url: s3Url, type: "POST", data: s3FormData, mimeType: "multipart/form-data", contentType: false, cache: false, processData: false }).done(function(data, status, formXHR) { x = formXHR['responseText'].toString(); var uploadedUrl = x.match("<Location>(.*)</Location>")[1]; if ($(this).attr('id').startsWith('inp')) { if ($(this).attr('id').startsWith('inp')) $('footer').css('background-image', 'url(' + uploadedUrl + ')'); footerBackground = $('footer').css('background'); } }).fail(function() { console.log("in ajax fail"); }.bind(this)); imgPromises.push(imgPromise1); imgPromise2 = $.ajax({ url: s3Url, type: "POST", data: s3FormData, mimeType: "multipart/form-data", contentType: false, cache: false, processData: false }).done(function(data, status, formXHR) { x = formXHR['responseText'].toString(); var uploadedUrl = x.match("<Location>(.*)</Location>")[1]; if ($(this).attr('id').startsWith('inp')) { if ($(this).attr('id').startsWith('inp')) $('footer').css('background-image', 'url(' + uploadedUrl + ')'); footerBackground = $('footer').css('background'); } }).fail(function() { console.log("in ajax fail"); }.bind(this)); imgPromises.push(imgPromise2); Promise.all(imgPromises.then(function() {});
如果任何諾言( imgPromise1
或imgPromise2
)失敗,那么它就不會進入Promise.all
。
我希望在任何情況下都應轉到Promise.all
。
您正在使用then
在錯誤的地方。
const Fail = function(error){this.error=error;};//special Fail type value
const isFail = o=>(o&&o.constructor)===Fail;//see if item passed is fail type
const isNotFail = o => !isFail(o);//see if item passed is not fail type
Promise.all(imgPromises
.map(
p=>Promise.resolve(p)/**convert to real promise*/
).map(
p=>p.catch(error=>new Fail(error))//single request failed, resolve with Fail value
)
)
.then(function (responses) {
// successes = responses.filter(isNotFail)
// failed = responses.filter(isFail)
})
.catch(function (err) {
//handle error
});
根據您使用的jQuery版本,您可以使用.catch
並返回catch可以解決承諾的內容。
jQuery的Promise.all($ .when)版本將不會拒絕任何延遲的(是jQuery promise實現)拒絕。
這僅是從版本3開始,因為jQuery在此版本之前推遲的行為不像標准化的承諾(現代瀏覽器中的原始承諾)那樣。
function makeRequest(num){//returning $.Deferred like $.ajax will var d = $.Deferred(); setTimeout(() => { if(num>1){//reject if number passed is higher than 1 d.reject("Rejecting over one"); return; } d.resolve(num) }, 10); return d.promise(); } $.when.apply(//jQueries Promise.all need apply to pass array of "promises" $, [1,2].map(//map numbers 1 and 2 to deferred 1 will resolve 2 rejects function(num){ return makeRequest(num) .catch(//catch rejected deferred function(error){return "error in:"+num; }//resolve with this ); } ) ).then(//both deferred (=jQuery promise like) are resolved function(){ console.log("it is done",[].slice.apply(arguments)); } )
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
但是,您嘗試使用jQuery版本2進行相同操作,但由於延期/承諾的實現與低於3的版本中的標准承諾不同,因此無法正常工作。您可以將Deferred轉換為真實承諾,但是如果您想支持較舊的瀏覽器,則可以需要Promise polyfil :
console.log("jQuery version",jQuery.fn.jquery); function makeRequest(num){//function returning jQuery deferred (could be $.ajax) var d = $.Deferred(); if(num>1){ //now this will throw an error throw("Rejecting over one"); } setTimeout(() => { d.resolve(num) }, 10); return d.promise(); } Promise.all( [1,2].map( function(num){ //convert deferred to real Promise (having catch) if makeRequest throws then promise is rejected return Promise.resolve().then(()=>makeRequest(num)) .catch( function(error){return "error in:"+num; }//resolve to error in... string ); } ) ).then( function(){ console.log("it is done",[].slice.apply(arguments)); } )
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
為了等到所有promise完成其任務(解決和/或拒絕),我們為每個promise return
catch()
值。
在這種情況下,我們使用.then()
接收所有信息。
我們可以使用filterInformation
輔助函數來過濾拒絕和已解決的數據。
例:
const mockResolvePromise = (message) => { return new Promise((resolve) => { resolve(message) }) } const mockRejectPromise = (messageError) => { return new Promise((_, reject) => { reject(messageError) }) } const ajax0 = mockResolvePromise({ nice: 'data' }) const ajax1 = mockRejectPromise('bad error'); const ajax2 = mockRejectPromise('semi bad error'); const ajax3 = mockRejectPromise('super bad error'); const ajax4 = mockResolvePromise({ hello: 'handsome' }) const promises = [ajax0, ajax1, ajax2, ajax3, ajax4]; // Now lets add catch const promisesWithCatch = promises.map(p => p.catch(e => { return { error: e } })) const filterInformation = (stuff) => { return stuff.reduce((prev, current) => { if (current.error) return { ...prev, errors: [...prev.errors, current.error] }; return { ...prev, data: [...prev.data, current] } }, { errors: [], data: [] }) } Promise.all(promisesWithCatch) .then(filterInformation) .then(data => console.log(data))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.