【问题标题】:$q.all aborts all promises when gets a 404 response$q.all 在收到 404 响应时中止所有承诺
【发布时间】:2017-07-14 15:13:40
【问题描述】:

我有一组要同时运行的承诺。我正在使用$q.all 来实现这一目标。当一个承诺返回 404 响应时,任何其他承诺都未实现。我希望能够在 $q.all 函数上单独获得错误承诺。我该怎么做?

var idPais = 13, idUF = 20;
var promises = [
    PaisAPI.list(), 
    UnidadeFederativaAPI.list(idPais), 
    MunicipioAPI.list(idUF)
];

$q.all(promises).then(
    function(values) {
        var paises = values[0].data;
        var ufs = values[1].data;
        var municipios = values[2].data;

        console.log('paises ', paises.length);
        console.log('ufs ', ufs.length);
        console.log('municipios ', municipios.length);

        $scope.paises = paises;
        $scope.unidadesFederativas = ufs;
        $scope.municipios = municipios;
    },
    function(error) {
        if (error.status == 500) {
            alert('Server error');
        }
        //when one of the promises get a 404 response any other one are unfulfilled
    }
);

【问题讨论】:

  • 当您收到 404 错误时,使各个承诺不会失败:在每个承诺上添加一个错误处理例程,以替换您要在服务器不可用时使用的值。

标签: javascript angularjs promise q


【解决方案1】:

我想这是所有这些东西都基于 Promises/A+ 规范的默认行为。

Documention 用于 JS 原生承诺状态:

Promise.all() 方法返回一个 Promise,当可迭代参数中的所有承诺都已解析或可迭代参数不包含任何承诺时,该 Promise 将解析。 它以第一个拒绝的承诺的原因拒绝。

从角度docsall()

返回一个单一的promise,它将用一个数组/哈希值解析,每个值对应于promise数组/哈希中相同索引/键的promise。 如果任何一个 Promise 以被拒绝的方式解决,这个产生的 Promise 将以相同的拒绝值被拒绝。

跨不同框架的所有实现都应该遵循并且实际上遵循这种方法。

作为一种解决方法,如果您的代码在 ajax 调用之后返回 404 错误,请尝试解决它而不是拒绝。我的意思是将这个错误视为一个积极的结果,并用一些特殊的值来解决它,比如false{error: 404, message: 'Not Found'}0——以便稍后显示客户端代码的差异。解决而不是拒绝应该让all() 等到所有承诺都完成。

【讨论】:

    【解决方案2】:

    在执行$q.all 之前重构代码以将值放在$scope 上:

    var idPais = 13, idUF = 20;
    var promiseObj = {};
    
    promiseObj.paises = PaisAPI.list()
      .then(function (response) {
        var paises = response.data;
        console.log('paises ', paises.length);
        $scope.paises = paises;
        return paises;
    }).catch(angular.identity);
    
    promiseObj.ufs = UnidadeFederativaAPI.list(idPais)
      .then(function (response) { 
        var ufs = response.data;
        console.log('ufs ', ufs.length);
        $scope.unidadesFederativas = ufs;
        return ufs;
    }).catch(angular.identity);
    
    promiseObj.municipos = MunicipioAPI.list(idUF)
      .then(function (response) {
        var municipios = response.data;
        console.log('municipios ', municipios.length);
        $scope.municipios = municipios;
        return municipios;
    }).catch(angular.identity);
    

    .catch(angular.identity);转换一个被拒绝的承诺到一个履行的承诺。每个 API 调用并行执行。

    使用$q.all 等待所有承诺完成,无论是履行还是拒绝:

    $q.all(promiseObj).then(function (dataObj) {
         console.log("All API calls complete");
         if (dataObj.paises.status) {
             console.log("paises failed with ",dataObj.paises.status);
         };
         if (dataObj.ufs.status) {
             console.log("ufs failed with ",dataObj.ufs.status);
         };
         if (dataObj.municipos.status) {
             console.log("municipos failed with ",dataObj.municipos.status);
         };
    }); 
    

    $q.all 与其他promise 库区分开来的一件事是AngularJS $q.all 接受promise 的对象哈希。

    欲了解更多信息,请参阅AngularJS $q Service API Reference - $q.all

    【讨论】:

      【解决方案3】:

      您需要确保不应该使$q.all() 失败的错误都由各个promise 处理。您应该确保处理所有您希望允许$q.all 正常完成的错误情况,但是如果有其他可能的错误仍然应该中止$q.all,那么应该使用$q.reject 传递这些错误。例如,在错误 404 上返回 -1 的长度:

      function handle404(error) {
          if (error.status == 404) {
              return { data: { length: -1 }};
          }
          return $q.reject(error)
      }
      var promises = [
          PaisAPI.list().catch(handle404), 
          UnidadeFederativaAPI.list(idPais).catch(handle404), 
          MunicipioAPI.list(idUF).catch(handle404)
      ];
      

      然后其余的代码和以前一样。或者在这些情况下只返回一个空数组:

      function handle404(error) {
          if (error.status == 404) {
              return { data: []};
          }
          return $q.reject(error)
      }
      

      但这与返回一个没有错误的空数组是无法区分的。

      【讨论】:

      • 您正在返回一个被拒绝的承诺。 $q.all 仍然会在第一个被拒绝的承诺上中止。如果你想转换一个被拒绝的承诺,return 一个值,而不是$q.reject
      • @georgeawg,OP 希望 404 错误不拒绝承诺。我假设(可能是错误的)在 $q.all() 处理程序中处理的其他错误(例如 503)仍应导致一切中止。这就是handle404 只处理 404 并传递其他错误的原因。
      • @Duncan,对不起。我的错。不是503错误码,是500错误码(服务器错误)。
      猜你喜欢
      • 2019-09-05
      • 1970-01-01
      • 1970-01-01
      • 2014-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-04
      • 2016-02-01
      相关资源
      最近更新 更多