当一个承诺被拒绝时,使$ q.all无声地失败

时间:2014-09-02 19:34:40

标签: javascript angularjs promise

我正在对一些地址进行地理编码,有时其中一些地址会失败。我希望能够得到剩下的结果并忽略失败的结果,这样我就可以在地图上显示其他坐标。目前$ q.all会在一个被拒绝时调用errorHandler,所以我失去了其他承诺的结果。

      $q.all(promises).then(function(coords) {
          for (var j = 0;j<coords.length;j+=1) {
              //success code
          }
      }, function(error) {
        console.log("Failed",error.type,error.message);
      });

3 个答案:

答案 0 :(得分:9)

Interrobang建议的解决方案很好(减去错误)但是如果你不喜欢让装饰器影响代码中的每一个承诺,你可以得到类似于allSettled的东西:

var suppress = function(x) { return x.catch(function(){}); } 
$q.all(promises.map(suppress)).then(function(coords) {
     for (var j = 0; j < coords.length ; j+=1) {
          //coords[j] contains the coords on success or is undefined on failure
      }
});

答案 1 :(得分:0)

你想要的是q.allSettled,这在Angular中没有实现。

这是relevant GitHub issue请求其实施。

以下是one possible implementation,名为allComplete,您可以将其添加到Angular应用中:

angular.module('App.services', ['ngResource'])
  .config( function($provide) {
    $provide.decorator("$q", ["$delegate", function($delegate) {
      var $q = $delegate;

      $q.allComplete = function(promises) {

        if(!angular.isArray(promises)) {
          throw Error("$q.allComplete only accepts an array.");
        }

        var deferred = $q.defer();
        var passed = 0;
        var failed = 0;
        var responses = [];

        angular.forEach(promises, function (promise, index) {
          promise
            .then( function(result) {
              console.info('done', result);
              passed++;
              responses.push(result);
            })
            .catch( function(result) {
              console.error('err', result);
              failed++;
              responses.push(result);
            })
            .finally( function() {
              if((passed + failed) == promises.length) {
                console.log("COMPLETE: " + "passed = " + passed + ", failed = " + failed);

                if(failed > 0) {
                  deferred.reject(responses);
                } else {
                  deferred.resolve(responses);
                }
              }
            })
          ;
        });

        return deferred.promise;

      };

      return $q;
    }]);
  })
;

答案 2 :(得分:0)

你可以只使用Angular的实现来解决你的问题,你要做的就是隔离其他函数中的异步调用,这个函数将返回一个promise,这个承诺将由你来管理。

让我们使用一个例子,假设您有四个异步调用,并且每个函数都使用授权控制调用一个端点,如果用户没有调用将失败的所有权限

  function getAllCatalogs() {
        return $q.all([
            $http.get(baseUrl + 'equipment-design/'),
            $http.get(baseUrl + 'engines-design/'),
            $http.get(baseUrl + 'suspension-design/'),
            $http.get(baseUrl + 'artifacts-design/')
        ]).then(function (data) {
            return data;
        });
    }

由于$ q.all需要所有承诺完成令人满意,如果之前的一个呼叫由于用户没有权限而失败,则整个呼叫将失败,但也许您对呼叫失败时感兴趣返回一个空数组或一个默认对象,所以你必须自己处理这个行为,要实现这一点,你必须创建一个函数,负责调用 $ http.get 服务并管理如何一旦呼叫失败或成功,将返回承诺,对于此示例,我们将该函数称为 getCatalogPromise ,并且在其参数中将是该服务的URL,代码将为:

   function getCatalogPromise(url) {
        var deferred = $q.defer();

        $http.get(url).then(function (response) {
            deferred.resolve(response)
        }, function () {
            deferred.resolve([]);
        })

        return deferred.promise;
    }

    function getAllCatalogs() {

        return $q.all([
            getCatalogPromise(baseUrl + 'equipment-design/'),
            getCatalogPromise(baseUrl + 'engines-design/'),
            getCatalogPromise(baseUrl + 'suspension-design/'),
            getCatalogPromise(baseUrl + 'artifacts-design/')
        ]).then(function (data) {
            return data;
        });
    }

如果您注意 getCatalogPromise 的代码,那么返回对服务的调用无关紧要,我们的延迟始终将处于解决状态,这就是 $ q .all 想要,唯一的区别是如果服务失败,我们返回一个空数组。