提问人:JBel 提问时间:8/16/2018 更新时间:8/16/2018 访问量:38
为对象中的所有成员调用 setTimeout() - 从不调用第一个成员,而是调用第二个成员。为什么?
Calling setTimeout() for all members in object - Never called for 1st member, and called for 2nd member. Why?
问:
我有一个 3D 数组(而不是 JS 对象),在我在此问题中发布的 SSCCE 中调用,它包含内部数组(而不是对象),每个数组包含多个 url 对象,每个对象都包含一个字段和一个字段。outerArray
url
interval
对于给定的内部数组(而不是对象),每个数组的字段值将是相同的。这就是它们的分组方式。interval
url
我的目的是,对于每个内部数组,我定期定期发送一个 AJAX 请求,并且此间隔的值由各个 url 中的字段确定。然后,根据 AJAX 请求的输出,我在 DOM 中进行了一些更改。interval
我从下面给出的代码中预料到这一点,但问题是它确实输入了第一个内部数组的函数(即间隔为 7 的 url),但随后从不调用 setTimeout()
函数,并继续调用下一个内部数组的函数(即间隔为 10 的 url),然后它确实调用了内部,它再次调用了该函数, 这个过程还在继续......next()
next()
setTimeout()
next()
我的问题是,为什么控件从不为第一个内部数组(间隔为 7 的 url)输入 setTimeout()
?为什么我会出现这种意外行为?
控制台输出:
Function loop iteration 0 for urls with interval 7
Function loop iteration 0 for urls with interval 10
setTimeout() called for urls with interval 10
Success for AJAX request for urls with interval 10
Function loop iteration 1 for urls with interval 10
setTimeout() called for urls with interval 10
Success for AJAX request for urls with interval 10
Function loop iteration 1 for urls with interval 10
setTimeout() called for urls with interval 10
Success for AJAX request for urls with interval 10
Function loop iteration 2 for urls with interval 10
setTimeout() called for urls with interval 10
Success for AJAX request for urls with interval 10
Function loop iteration 2 for urls with interval 10
...
脚本 .js:
$(document).ready(function() {
var outerArray = {
0 : {
0 : {
url: "abc.example.com",
interval: 7
},
1 : {
url: "def.example.com",
interval: 7
}
},
1 : {
0 : {
url: "ghi.example.com",
interval: 10
}
}
};
for (var innerArrayKey in outerArray) {
var innerArray = outerArray[innerArrayKey];
(function next(index) {
console.log("Function loop iteration " + index + "for urls with interval " + innerArray[0]["interval"]);//check
setTimeout(function() {
console.log("setTimeout() called for urls with interval " + innerArray[0]["interval"]);//check
$.ajax({
url: "http://xxx.yyy.xx.yy/testAsynchronousJSRequests/ajax.php",
method: "post",
data: { innerArray : innerArray },
success: function(dataReturned, stringStatus, jqXHR) {
console.log("Success for AJAX request for urls with interval " + innerArray[0]["interval"]);//check
next(index+1);
},
error: function(jqXHR, stringStatus, stringExceptionThrown) {
console.log("Error in AJAX request " + innerArray[0]["interval"]);//check
}
});
}, (innerArray[0]["interval"]*1000) );
})(0);
}
});
ajax .php:
<?php
print_r($_POST["innerArray"]);
?>
索引 .php:
<!DOCTYPE html>
<html>
<head>
<script src="jquery-3.3.1.min.js"></script>
<script src="scripts.js"></script>
</head>
<body>
</body>
</html>
答:
这与 setTimeout 的范围有关,使用您当前的代码时,当执行 setTimeout 时,它会读取 innerArray 的最后一个值,该值指向间隔为 10 的数组。有 2 种方法(至少)可以解决这个问题:
1) 使用立即调用的函数包装器为每个 setTimeout 创建一个单独的作用域,并正确引用 innerArray 变量:
$(document).ready(function() {
var outerArray = {
0: {
0: {
url: "abc.example.com",
interval: 7
},
1: {
url: "def.example.com",
interval: 7
}
},
1: {
0: {
url: "ghi.example.com",
interval: 10
}
}
};
for (var innerArrayKey in outerArray) {
var innerArray = outerArray[innerArrayKey];
(function next(index) {
console.log("Function loop iteration " + index + " for urls with interval " + innerArray[0]["interval"]); //check
setTimeout(function(innerArray) {
return function() {
console.log("setTimeout() called for urls with interval " + innerArray[0]["interval"]); //check
$.ajax({
url: "http://xxx.yyy.xx.yy/testAsynchronousJSRequests/ajax.php",
method: "post",
data: {
innerArray: innerArray
},
success: function(dataReturned, stringStatus, jqXHR) {
console.log("Success for AJAX request for urls with interval " + innerArray[0]["interval"]); //check
next(index + 1);
},
error: function(jqXHR, stringStatus, stringExceptionThrown) {
console.log("Error in AJAX request " + innerArray[0]["interval"]); //check
}
});
}
} (innerArray), (innerArray[0]["interval"] * 1000));
})(0);
}
});
2) 使用 ES6 let 关键字为每个迭代创建一个单独的范围:
$(document).ready(function() {
var outerArray = {
0: {
0: {
url: "abc.example.com",
interval: 7
},
1: {
url: "def.example.com",
interval: 7
}
},
1: {
0: {
url: "ghi.example.com",
interval: 10
}
}
};
for (var innerArrayKey in outerArray) {
let innerArray = outerArray[innerArrayKey];
(function next(index) {
console.log("Function loop iteration " + index + " for urls with interval " + innerArray[0]["interval"]); //check
setTimeout(function() {
console.log("setTimeout() called for urls with interval " + innerArray[0]["interval"]); //check
$.ajax({
url: "http://xxx.yyy.xx.yy/testAsynchronousJSRequests/ajax.php",
method: "post",
data: {
innerArray: innerArray
},
success: function(dataReturned, stringStatus, jqXHR) {
console.log("Success for AJAX request for urls with interval " + innerArray[0]["interval"]); //check
next(index + 1);
},
error: function(jqXHR, stringStatus, stringExceptionThrown) {
console.log("Error in AJAX request " + innerArray[0]["interval"]); //check
}
});
}, (innerArray[0]["interval"] * 1000));
})(0);
}
});
您可以查看此内容以了解更多信息: JavaScript 闭包:For 循环中的 setTimeout
上一个:此代码片段如何执行闭包?
评论