如何使用promise处理失败的ajax请求

时间:2018-06-11 14:56:59

标签: javascript jquery ajax 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() {});
&#13;
&#13;
&#13;

如果任何承诺(imgPromise1imgPromise2)失败,那么它就没有转到Promise.all

我希望在任何情况下都应该转到Promise.all

3 个答案:

答案 0 :(得分:1)

您在错误的地方使用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
});

MDN page for Promise.all

答案 1 :(得分:0)

根据您使用的jQuery版本,您可以使用.catch并返回承诺将解决的catch中的内容。

jQuery的Promise.all($ .when)版本不会拒绝任何延迟(是jQuery承诺实现)拒绝。

这只是自版本3以来,因为在此版本之前jQuery的行为不像标准化的承诺(现代浏览器原生的承诺)。

&#13;
&#13;
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));
  }
)
&#13;
<script
  src="https://code.jquery.com/jquery-3.3.1.min.js"
  integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
  crossorigin="anonymous"></script>
&#13;
&#13;
&#13;

但是,您尝试使用jQuery的第2版并且它不会起作用,因为延迟/承诺的实现与低于3的版本中的标准承诺不同。您可以将延迟转换为真正的承诺但是如果您想要要支持您需要的旧浏览器Promise polyfil

&#13;
&#13;
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));
  }
)
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

要等到所有承诺完成任务(解决和/或拒绝),我们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>