使用closure。让我给你看一个简单的例子
// JavaScript on Client-Side
window.onload = function() {
var f = (function() {
for (i = 0; i < 3; i++) {
(function(i){
var xhr = new XMLHttpRequest();
var url = "closure.php?data=" + i;
xhr.open("GET", url, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText); // 0, 1, 2
}
};
xhr.send();
})(i);
}
})();
};
// Server-Side (PHP in this case)
<?php
echo $_GET["data"];
?>
在你的情况下......用闭包包装异步调用/函数
for (var i=0; i< this.selectedAvailableUnits.length; i++) {
(function(i) { // <--- the catch
var unit = this.selectedAvailableUnits[i];
var unitId = unit.unitId;
var url = '/incident/' + currentIncidentId + '/assignUnit/' + unitId
$http.post(url).then(function(response) {
// DOING SOMETHING
}, function(error) {
alert(error);
});
})(i); // <---- (the i variable might be omitted if it's not needed)
}
以下部分与问题没有直接关系,而是与与此答案相关的 cmets。
在 cmets 中提到的jsFiddle 上提交的示例如下所示是错误的,因此它不能证明任何事情。
确实,这个 sn-p,即使不使用闭包,也会产生 3 次“Hello Kitty”;实际上,如果您将 console.log() 方法替换为 alert() 方法,您会看到它产生了 6、9 甚至 12 次“Hello Kitty”。那么,到底是怎么回事;)怎么可能在三个迭代的循环中弹出警报窗口六、九或十二次?!
// your example (a) // my comments
//
var f = (function() {
for (i = 0; i < 3; i++) {
//(function(){ // this way you can't have multiple scopes
var xhr = new XMLHttpRequest();
var url = "closure.php?data=your-data"; // use /echo/html/ for testing on jsfiddle.net
xhr.open("GET", url, true); // use POST for testing on jsfiddle.net
xhr.onreadystatechange = function () { // this way you might catch all readyStage property values
callback(); // this way the callback function will be called several times
};
xhr.send();
//})();
}
})();
var callback = function() {
console.log("Hello Kitty"); // or use alert("Hello Kitty");
};
输出:
GET http://fiddle.jshell.net/_display/closure.php?data=your-data 404 (NOT FOUND)
(9) Hello Kitty
如您所见,我们有一个错误和连续 9 个“Hello Kitty”输出 :) 在我更改上面的函数之前,让我们看看 两件重要的事情
第一
onreadystatechange 事件存储一个函数或一个引用,每次readyState 属性更改时自动调用,而status 属性保持 XMLHttpRequest 对象的状态。
readyState 属性可能值
- 0:请求未初始化
- 1:建立服务器连接
- 2:收到请求
- 3:处理请求
- 4:请求完成,响应准备就绪
status属性可能值
第二
正如我在 cmets 中所说,jsfiddle.net 在不进行一些更改的情况下测试异步 sn-ps 是不可靠的。换句话说,GET 方法应该更改为POST,url 属性必须更改为此链接/echo/html/(更多选项请查看jsFiddle documentation)
现在,让我们从上面的示例中更改(并遵循代码中的 cmets)
// corrected example (b)
//
var f = (function() {
for (i = 0; i < 3; i++) {
//(function(i){ // uncomment this line for the 3rd output
var xhr = new XMLHttpRequest();
var url = "/echo/html";
var data = "data";
xhr.open("POST", url, true);
xhr.onreadystatechange = function () {
//if (xhr.readyState == 4 && xhr.status == 200) { // uncomment this line for the 4th output
callback(i, xhr.readyState); // uncomment this line for the 4th output
//}
};
xhr.send(data);
//})(i); // uncomment this line for the 3rd output
}
})();
var callback = function(i, s) {
console.log("i=" + i + " - readyState=" + s + " - Hello Kitty");
};
第一个输出://六个输出
(4) i=3 - readyState=1 - Hello Kitty // four outputs related to readyState value 'server connection established'
i=3 - readyState=2 - Hello Kitty // related to readyState value 'request received'
i=3 - readyState=4 - Hello Kitty // related to readyState value 'request finished and response is ready'
第二个输出://六个输出
(2) i=3 - readyState=1 - Hello Kitty // two outputs related to readyState value 'server connection established'
i=3 - readyState=2 - Hello Kitty // related to readyState value 'request received'
(3) i=3 - readyState=4 - Hello Kitty // three outputs related to readyState value 'request finished and response is ready'
没有在示例 (b) 中进行任何更改,我们得到了两个不同的输出。正如你所看到的,不同的 readyState 属性值的不同输出已经产生了。
但i 的值保持不变。
3rd output: // 在上面示例 (b) 中显示的第三个输出的行取消注释后
i=0 - readyState=2 - Hello Kitty // related to readyState value 'request received'
i=0 - readyState=4 - Hello Kitty // related to readyState value 'request finished and response is ready'
i=1 - readyState=2 - Hello Kitty // ...
i=1 - readyState=4 - Hello Kitty // ...
i=2 - readyState=2 - Hello Kitty
i=2 - readyState=4 - Hello Kitty
所以,在取消注释保存i 作为参数的函数后,我们看到i 的值已被保存。但这仍然是不正确的,因为有六个输出,我们只需要三个。由于我们不需要XMLHttpRequest 对象的readyState 或status 属性的所有值,因此我们取消注释第四个输出所需的两行
第 4 个输出:// 取消注释上面示例 (b) 中显示的第 4 个输出的行后 - 最后是三个输出
i=0 - readyState=4 - Hello Kitty
i=1 - readyState=4 - Hello Kitty
i=2 - readyState=4 - Hello Kitty
最后,这应该是 sn-p 的正确版本,这就是我们所需要的。
另一个全能、无所不能的机制(正如我之前形象地说过的)是 bind() 函数,我不喜欢它,因为它比闭包慢。