我在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';
,但没有成功。
答案 0 :(得分:2)
首先,angular.forEach
不支持中断(请参阅here和here)
第二次,break
语句必须直接嵌套在循环中,即使它是for
或while
循环。
最后,.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 投掷会产生所需的“停止”效果。
如果抛出在实际代码中不起作用,那么看起来其他东西是错误的。