[英]ajax function in for loop not updating DOM even with setTimeout
我正在编写一个函数,在页面加载时使用ajax从后端服务器获取指令。 我的ajax代码根据数字获取指令,并使用jquery和控制台使用此<p id="loadText"></p>
元素中的变量response.setText打印指令。 这是我的ajax功能:
function ajaxFetch(s) {
var success = false;
$.ajax({
type: "POST",
url: "post.php",
data: {
step: s
},
async: false,
dataType: 'JSON',
success: function (response) {
$("#loadText").text(response.stepText);
console.log(response.stepText);
success = true;
}
});
return success;
}
我试图使用另一个函数循环遍历步骤,无论有多少,但这里是我遇到的问题:
ajaxFetch()
直到上次执行才更新DOM setTimeout()
而没有更新DOM ajaxFetch()
过快循环 response.stepText
按时在控制台中打印,但不会按时更新DOM 这是我尝试过的示例循环:
function uploadSteps(maxStep) {
for (var x = 1; x <= maxStep; x++){
setTimeout(ajaxFetch(x), 20);
}
}
对不起,这是太长了,并提前感谢。
当你的for循环完成时,比如20次迭代,你在ajaxFetch中的ajax调用只会收到前几次调用的响应,你最后看到的是最后一次ajax调用的响应。 您可以使用此链接了解异步调用如何在javascript中运行https://rowanmanning.com/posts/javascript-for-beginners-async/
所以答案是,你需要等到第一个ajax调用完成后再以20ms的超时再次调用该方法,就像这样
var globalMaxSteps = 1;
var startIndex = 1;
function ajaxFetch(s) {
$.ajax({
type: "POST",
url: "post.php",
data: {
step: s
},
async: false,
dataType: 'JSON',
success: function (response) {
$("#loadText").text(response.stepText);
console.log(response.stepText);
startIndex++;
if(startIndex <= globalMaxSteps) {
setTimeout(function(){
ajaxFetch((startIndex);
},20);
} else {
console.log("All Iterations complete");
}
}
});
}
function uploadSteps(maxStep) {
startIndex = 1;
globalMaxSteps = maxStep;
setTimeout(function(){
ajaxFetch(startIndex);
},20);
}
首先,我们需要修复uploadSteps
函数中的错误:
function uploadSteps(maxStep) {
// here change `var x` to `let x` to avoid problems
// like here - https://stackoverflow.com/q/750486/5811984
for (let x = 1; x <= maxStep; x++){
setTimeout(function() {
// notice how here ajaxFetch(x) is wrapped into a function,
// otherwise it gets called right away
ajaxFetch(x)
}, 20);
}
}
现在这是另一个问题 - 所有的setTimeout都将被调用20ms
延迟,这意味着它们将同时执行,但是在uploadSteps()
之后约20ms。
让我们看看当maxStep=3
时会发生什么(假设你的CPU非常快,因为这与理解问题无关):
Time passed | what happens
--------------------------
0ms | setTimeout(ajaxFetch(1), 20) is called
0ms | setTimeout(ajaxFetch(2), 20) is called
0ms | setTimeout(ajaxFetch(3), 20) is called
20ms | ajaxFetch(1) is called
20ms | ajaxFetch(2) is called
20ms | ajaxFetch(3) is called
所以当你看到所有ajaxFetch
同时被调用时,我假设这不是你需要的。 您可能正在寻找的是:
Time passed | what happens
--------------------------
0ms | setTimeout(ajaxFetch(1), 20) is called
0ms | setTimeout(ajaxFetch(2), 40) is called
0ms | setTimeout(ajaxFetch(3), 60) is called
20ms | ajaxFetch(1) is called
40ms | ajaxFetch(2) is called
60ms | ajaxFetch(3) is called
只需对代码稍作修改即可实现
function uploadSteps(maxStep) {
for (let x = 1; x <= maxStep; x++){
setTimeout(function() {
ajaxFetch(x)
}, 20 * x); // change delay from 20 -> 20 * x
}
}
此外,您似乎不需要从ajaxFetch()
返回任何内容,因此最好使其成为异步,因此它不会阻止代码执行:
function ajaxFetch(s) {
$.ajax({
type: "POST",
url: "post.php",
data: {
step: s
},
// async: false, -- remove this, it's true by default
dataType: 'JSON',
success: function (response) {
$("#loadText").text(response.stepText);
console.log(response.stepText);
}
});
}
就算你其实需要为返回的东西fetchAjax()
它更好地保持它的异步和使用回调/承诺。 jQuery实际上强烈反对在任何情况下使用async: false
。
如果你添加setTimeout
的原因是为了确保所有步骤按顺序执行,那么这不是正确的方法。 问题是:
最好从ajaxFetch()
添加一个回调,该回调将在ajax提取完成后调用,然后在收到回调后调用下一个ajaxFetch()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.