2014-09-02 50 views
4

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

 $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); 
     }); 
+0

如果失败而不是拒绝,您可以使用空值或无值(未定义)来解析,以便将相应失败值的坐标数组设置为空。 – PSL 2014-09-02 19:42:52

回答

0

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

这是relevant GitHub issue要求其实施。

这里是one possible implementation,叫allComplete,您可以添加到您的角度应用:

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; 
    }]); 
    }) 
; 
+0

这看起来像它有一个很大的错误 - 响应中的承诺顺序不能保证。当然你的意思是'响应[指数] =结果'而不是'respond.push(结果)'对吗? – 2014-09-03 06:08:54

+8

“我只是发布了代码,我不知道它是如何工作的”这个概念对我来说很恐怖。对不起,如果你在这里发布代码,并且它有错误的地方修复它们。 – 2014-09-03 07:27:05

9

通过进行插入提出的解决方案是好的(减去错误),但如果你不喜欢有装饰影响每一个承诺在你的代码,你可以得到类似的东西来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 
     } 
}); 
+0

我不喜欢这种语义,所以很高兴看到更清晰的版本。但我确实喜欢简单,再加上这实际上解决了所述的问题。+1 – 2014-09-03 06:44:14

+0

我不确定这里的语义如何更好 - 这是一个丑陋的解决方案,类似臭名昭着的“全部抓住”,说“压制所有可能出错” - 如果网络请求不起作用(但有可能是服务器上的坐标)在这段代码中将无法处理它。这段代码解决了“解决”问题的一个非常狭窄的形式 - 它将在OP的情况下起作用,并且非常简单,但在“解决”一系列承诺的一般情况下,它并不会奏效。 – 2014-09-03 06:47:57

0

你可以只使用角执行你所要做的是隔离在其他函数在异步调用解决您的问题要回报一个承诺,这个承诺将会为你管理。

让我们用一个例子,让我们说,你有四个异步调用和每个函数调用与授权控制端点,如果用户不具有所有的权限调用是要失败的

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它does'n无论什么呼叫到服务我们的递延始终是要在解决状态,这是什么$ q.all想,唯一的区别是如果服务失败,我们返回一个空数组。