我正在编写一个函数,在页面加载时使用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);
}
}
对不起,这太长了,并提前感谢。
答案 0 :(得分:1)
首先,我们需要修复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()
。
答案 1 :(得分:1)
当你的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);
}