angularjs 在 $http 成功中打破 forEach
Posted
技术标签:
【中文标题】angularjs 在 $http 成功中打破 forEach【英文标题】:angularjs break forEach in $http success 【发布时间】:2015-11-16 21:05:12 【问题描述】:我在 Ionic 框架中有以下代码,
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);
);
);
);
);
;
它确实是在循环中同步发送 http 请求,并在 $http 错误时中断,就像我想要的那样。但是我如何在 $http 成功中打破循环?我试过throw 'Scan stopped';
和$q.reject('Scan stopped');
但没有成功。
【问题讨论】:
我不太清楚你想要实现什么整体目标。但我认为最好将异步 http post 调用包装到 promise 中并相应地调用 resolve 或 reject。关于打破循环,我在您的代码中看不到任何循环。但是您始终可以执行 if-else 语句来检查 stopScan 值。如果是真的,只需调用 break 将打破 JS 中的循环 在你的例子中,stopScan
已经是true
- 那么,为什么还要循环呢?但总的来说,stopScan
应该来自哪里?
【参考方案1】:
首先,angular.forEach
不支持中断(参见here 和here)
第二,break
语句必须直接嵌套在循环内,即使是for
或while
循环。
最后,.success
是异步发生的,在循环执行之后,所以通过其他方式打破那里本来是反正没意义。
您似乎希望 stopScan
在其他地方异步设置(例如,响应用户的点击),但您必须确定停止的确切含义 - 是否意味着“不做任何更多 $http.post
requests”,或者它的意思是“发出所有请求,但不处理响应?”。 (您的示例似乎暗示了后者,因为您试图在 .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);
)
【讨论】:
【参考方案2】:如果您想使用并行 HTTP 请求运行,请使用 @NewDev 的答案。
但是,如果您想坚持串行请求,那么“跳出循环”再简单不过了。
您需要做的就是抛出,它不会因此而中断,但会将构造的 Promise 链发送到错误路径。在停止点,不会有未返回的请求,也不会再发送请求。
我会写这样的东西,使用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 投掷会产生所需的“停止”效果。
如果 throw 在实际代码中不起作用,那么似乎还有其他问题。
【讨论】:
唯一的问题是你在真正应该成功的事情上抛出了一个错误(我相信;我不确定stopScan
是否应该是一个错误)。是的,您可以立即捕捉到它,但从语义上讲,这有点不对劲。
@trysis,为了流量控制而扔进一个承诺链是完全合法的。以上是关于angularjs 在 $http 成功中打破 forEach的主要内容,如果未能解决你的问题,请参考以下文章
为啥不推荐使用 AngularJS $http 成功/错误方法?从 v1.6 中删除?
为啥不推荐使用 AngularJS $http 成功/错误方法?从 v1.6 中删除?
angularJS中的$http.get错误——成功不是函数[重复]
$ http get不会在AngularJS中抛出成功或错误[重复]