繁体   English   中英

即使使用setTimeout,for循环中的ajax函数也不会更新DOM

[英]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
  • for循环通过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的原因是为了确保所有步骤按顺序执行,那么这不是正确的方法。 问题是:

  • 假设服务器响应第一个请求需要100毫秒,第二个请求需要10毫秒。 即使延迟20ms,第二个请求也将首先执行。 只是增加延迟不是解决方案,因为:
  • 如果您的服务器响应延迟的速度要快得多,那么您将为用户引入不必要的等待。

最好从ajaxFetch()添加一个回调,该回调将在ajax提取完成后调用,然后在收到回调后调用下一个ajaxFetch()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM