Функция ajax для цикла не обновляет DOM даже с помощью setTimeout - PullRequest
0 голосов
/ 06 июня 2018

Я пишу функцию для использования ajax для получения инструкций от внутреннего сервера во время загрузки страницы.Мой код ajax выбирает инструкции на основе числа и печатает инструкции, используя переменную response.setText в этом элементе <p id="loadText"></p>, используя jquery и консоль.Вот моя функция 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);
   }
}

Извините, что так долго и спасибозаранее.

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

К тому времени, когда ваш цикл for завершится, скажем, за 20 итераций, ваш ajax-вызов в ajaxFetch получит ответ только для первых нескольких вызовов, и в конце вы увидите ответ на последний вызов ajax.Вы можете использовать эту ссылку, чтобы понять, как асинхронные вызовы работают в javascript https://rowanmanning.com/posts/javascript-for-beginners-async/

Так что ответ таков: вам нужно дождаться завершения первого вызова ajax и затем снова вызвать метод с тайм-аутом 20 мс, напримерэто

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);
}
0 голосов
/ 06 июня 2018

Во-первых, нам нужно исправить ошибки в функции 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, то есть все они будутбудет выполняться одновременно, но через ~ 20 мс после вызова uploadSteps().

Давайте посмотрим, что произойдет, когда maxStep=3 (при условии, что ваш процессор очень быстрый, потому что это не имеет значения для понимания проблемы):

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);
        }
    });
}

Даже если на самом деле do нужно что-то вернуть для fetchAjax(),лучше держать его асинхронным и использовать обратные вызовы / обещания. jQuery на самом деле настоятельно не рекомендует использовать async: false в любом случае.


Если причина, по которой вы добавили setTimeout s, заключается в том, чтобы убедиться, что все шаги выполнены по порядку, то этоне правильный способ сделать это.Проблемы:

  • Допустим, серверу потребовалось 100 мс для ответа на первый запрос и 10 мс для второго.Даже с задержкой в ​​20 мсек второй запрос будет выполнен первым.И просто увеличение задержки не является решением, потому что:
  • Если ваш сервер реагирует намного быстрее, вы вводите ненужное ожидание для пользователя.

Лучше добавитьобратный вызов из ajaxFetch(), который будет вызван, когда будет выполнена выборка ajax, а затем вы позвоните в следующий ajaxFetch() после получения обратного вызова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...