angularjs在$ http成功时打破forEach

时间:2015-08-23 09:59:33

标签: angularjs ionic-framework promise ionic

我在Ionic框架中有以下代码,

ListView

它是在同步循环中发送http请求,并在$ http错误中断,完全像我想要的那样。但是我如何打破$ http成功的循环?我尝试了var stopScan = false; $scope.StopScan = function() { stopScan = true; }; $scope.ScanContacts = function() { Contacts.unchecked().then(function(contacts) { var promise = $q.all(null); angular.forEach(contacts, function(contact) { promise = promise.then(function() { return $http.post(apiEndpoint+'/check', {number: contact.number}) .success(function(res) { Contacts.update(contact.id, res); if(stopScan) // do break loop; }) .error(function(err) { console.log(err); }); }); }); }); }; throw 'Scan stopped';,但没有成功。

2 个答案:

答案 0 :(得分:2)

首先angular.forEach不支持中断(请参阅herehere

第二次break语句必须直接嵌套在循环中,即使它是forwhile循环。

最后.success异步发生, 循环执行后,所以通过其他方式打破无论如何都没有意义。

好像你希望stopScan在其他地方异步设置(例如,响应来自用户的点击),但你必须确切地决定停止它意味着什么 - 它是否意味着“不要再做$http.post个请求,或者它是否意味着“发出所有请求,但不处理响应?”。 (您的示例似乎暗示后者,因为您试图在.success中处理它,但您应该知道,POST通常意味着在服务器上进行了更改。

您必须明白,一旦您启动HTTP请求,它就会消失(或者它正在等待,取决于最大数量的连接,这取决于浏览器)。

所以,你可以做的是立即并行地触发所有请求,然后手动“超时”($http支持基于承诺的timeout)那些没有的请求已完成:

var stopScanTimeout = $q(function(resolve){
  $scope.stopScan = function(){
    resolve();
  }
})

var promises = [];
angular.forEach(contacts, function(contact) {
  var httpPromise = $http({ method:  "POST",
                            url:     apiEndpoint+'/check', 
                            data:    {number: contact.number},
                            timeout: stopScanTimeout })
                         .then(function(response){ return response.data; },
                               function(error)   { return {error: error};});
  promises.push(httpPromise);
});

然后你可以一起处理所有结果,如果没有及时完成,有些会是“错误”(但是“软”错误):

$q.all(promises).then(function(results){
  for (var i = 0; i < results.length, i++){
    var result = results[i];

    if (result.error) continue;

    // otherwise, process the result
    Contacts.update(contact.id, result);
  }
})

答案 1 :(得分:1)

如果您想使用并行HTTP请求运行,请使用@NewDev的答案。

但是如果你想坚持使用串行请求,那么“打破循环”就不会更简单了。

您需要做的就是抛出,这不会破坏,但会将构造的承诺链发送到其错误路径。在停止点,将不会有未退回的请求,也不会再发送请求。

我会写这样的东西,使用contacts.reduce(...)构建链。

$scope.ScanContacts = function() {
    return Contacts.unchecked().then(function(contacts) {
        return contacts.reduce(function (p, contact) {
            return p.then(function() {
                return $http.post(apiEndpoint + '/check', { number: contact.number })
                .then(function(res) {
                    if(stopScan) throw new Error('scan stopped');
                    Contacts.update(contact.id, res);//you can choose to service the last response or not but placing this line above or below the throw line.
                }, function(err) {
                    // As the second .then param, this callback will catch any http errors but not the 'scan stopped' error.
                    // By catching http errors, the scan will be allows to continue.
                    // To stop on http error, either remove this callback or rethrow the error.
                    console.log(err);
                });
            });
        }, $q.when());
    });
};

Here's evidence 投掷会产生所需的“停止”效果。

如果抛出在实际代码中不起作用,那么看起来其他东西是错误的。