本周末,我在Javascript中遇到了处理竞争条件的特殊问题。
以下是给我问题的代码:
function myFunction(requestObj, myArray) {
for(var i=0;i<myArray.length;i++) {
//AJAX call
makeAjaxCall(requestObj, function(data) {
//Callback for the ajax call
//PROBLEM : HOW CAN I ACCESS VALUE OF 'i' here for the iteration for which the AJAX call was made!!!
}
}
}
&#13;
获取&#39; i&#39;的价值在AJAX回调中不会给我预期的值,因为当AJAX呼叫响应回来时,&#39; for&#39;循环会经过多次迭代。
为了解决这个问题,我采用了以下方法:
function myFunction(requestObj, myArray) {
var i = 0;
function outerFunction() {
makeAjaxCall(requestObj, innerFunction);
}
function innerFunction(data) {
i++;
if(i<myArray.length) {
outerFunction();
}
}
outerFunction();
}
&#13;
这是正确的做法吗?假设它是我无法修改的第三方AJAX库调用,我可以通过其他方式改进这一点。
答案 0 :(得分:4)
你只需要使用一个闭包:
function myFunction(requestObj, myArray) {
for(var i=0;i<myArray.length;i++) {
//AJAX call closed over i
(function(i) { // wrap your call in an anonymous function
makeAjaxCall(requestObj, function(data) {
// i is what you think it is
}
})(i) // pass i to the anonymous function and invoke immediately
}
}
答案 1 :(得分:0)
问题是,您传递给ajax调用的回调有一个持久引用到i
,而不是创建它时的值的副本。
你的方法很好除了它等待第二次ajax调用直到第一次完成,然后等待第二次完成才能完成第三次,等等。除非你拥有为了做到这一点(我得到你没有的印象),最好让它们重叠。
有两种选择:
使用构建器功能:
function myFunction(requestObj, myArray) {
for(var i=0;i<myArray.length;i++) {
//AJAX call
makeAjaxCall(requestObj, buildHandler(i));
}
function buildHandler(index) {
return function(data) {
// Use `index` here
};
}
}
现在,处理程序引用index
,而不是i
,而不是Function#bind
。
使用function myFunction(requestObj, myArray) {
for(var i=0;i<myArray.length;i++) {
//AJAX call
makeAjaxCall(requestObj, function(index, data) {
// Use index here
}.bind(null, i));
}
}
:
Function#bind
this
创建一个函数,在调用时,将调用具有特定bind
值的原始函数(我们没有使用上面的值)和您传递的任何参数using (PowerShell PowerShellInstance = PowerShell.Create())
{
PowerShellInstance.AddScript(@"cd (Join-Path (Join-Path $env:HOMEDRIVE $env:HOMEPATH) desktop); $null >> newfile.txt");
PowerShellInstance.Invoke();
}
- 然后是赋予绑定函数的任何参数。
我更喜欢#1:读取很清楚并且没有创建一堆不必要的函数(理论上,#2每个循环创建两个函数而不是一个)。
答案 2 :(得分:0)
还有另外两种方法:使用bind,使用闭包
使用bind:
function myFunction(requestObj, myArray) {
for(var i=0;i<myArray.length;i++) {
makeAjaxCall(requestObj, function(idx,data) {
//idx will be correct value
}.bind(null,i));
}
}
使用闭包:
function myFunction(requestObj, myArray) {
for(var i=0;i<myArray.length;i++) {
(function(idx){
makeAjaxCall(requestObj, function(data) {
//idx will be correct value
});
})(i);
}
}
还有第三种方法,使用另一个函数来创建回调
function myFunction(requestObj, myArray) {
function makeCB(idx){
return function(){
//do stuff here
}
}
for(var i=0;i<myArray.length;i++) {
makeAjaxCall(requestObj, makeCB(i));
}
}