$ q.all在获得404响应时中止所有承诺

时间:2017-07-14 15:13:40

标签: javascript angularjs promise q

我有一套我希望同时运行的承诺。我正在使用$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
    }
);

3 个答案:

答案 0 :(得分:3)

我认为这是默认行为,符合Promises / A +规范,所有这些都建立在这些规范之上。

JS原生承诺的

Documention声明:

  

Promise.all()方法返回一个Promise,它在iterable参数中的所有promise都已解析或者iterable参数不包含promise时解析。 它拒绝了第一个承诺拒绝的原因。

all()的角度docs

  

返回将使用值的数组/散列解析的单个promise,每个值对应于promises数组/散列中相同索引/键的promise。 如果任何承诺通过拒绝得到解决,则此结果承诺将被拒绝并具有相同的拒绝价值。

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

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

答案 1 :(得分:2)

重新计算代码,以便在执行$scope之前将值放在$q.all上:

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接受promises的对象哈希。

有关详细信息,请参阅AngularJS $q Service API Reference - $q.all

答案 2 :(得分:1)

您需要确保不应使$q.all()失败的错误全部由个别承诺处理。您应该确保处理允许$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)
}

但是这不能与没有错误的空数组区别开来。