Как Вы заставляете код JavaScript выполниться *в порядке*

Хорошо, таким образом, я ценю, что JavaScript не является C# или PHP, но я продолжаю возвращаться к проблеме в JavaScript - не с самим JS, но моим использованием его.

У меня есть функция:

function updateStatuses(){

showLoader() //show the 'loader.gif' in the UI

updateStatus('cron1'); //performs an ajax request to get the status of something
updateStatus('cron2');
updateStatus('cron3');
updateStatus('cronEmail');
updateStatus('cronHourly');
updateStatus('cronDaily');

hideLoader(); //hide the 'loader.gif' in the UI

}

Вещь вследствие острого желания JavaScript перейти вперед в коде, загрузчик никогда не появляется, потому что функция 'hideLoader' работает прямо за.

Как я могу зафиксировать это? Или другими словами, как я могу заставить функцию JavaScript выполниться в порядке, который я пишу этому на странице...

20
задан Old Pro 25 January 2019 в 07:53
поделиться

7 ответов

Как указывали другие, вы не хотите выполнять синхронную операцию. Примите Async, это то, что означает A в AJAX.

Я просто хотел бы упомянуть отличную аналогию для sync v / s async. Вы можете прочитать сообщение целиком на форуме GWT , я просто привожу соответствующие аналогии.

Представьте, что вы…

Вы сидите на диване и смотрите телевизор и, зная, что у вас закончилось пиво, вы просите супругу доставить удовольствие {{1 }} сбегите в винный магазин и принесите вам немного. Как только вы видите, как ваш супруг (а) выходит через парадную дверь, вы встаете с дивана, катитесь на кухню и открываете холодильник. К вашему удивлению, здесь нет пива !

Ну, конечно, пива нет, ваша супруга все еще едет в винный магазин . Вам нужно подождать, пока [s] он не вернется, прежде чем вы сможете ожидать, что выпьет пива.

Но вы говорите, что хотите синхронизировать? Представьте себе еще раз ...

... супруг выходит за дверь ... теперь, весь мир вокруг вас останавливается, вы не дышите, ответьте на {{ 1}} или закончите смотреть шоу , пока [s] он бежит через город за вашим пивом. Вы просто можете сидеть там, не двигая мускулами, и посинеть, пока не потеряете сознание ... проснувшись через некоторое неопределенное время в окружении { {1}} Скорая помощь и супруга говорят: "Ой, эй, я принес ваше пиво".

Это именно то, что происходит, когда вы настаиваете на синхронном вызове сервера.

1
ответ дан 29 November 2019 в 23:23
поделиться

У нас есть нечто подобное в одном из наших проектов, и мы решили это с помощью счетчика. Если вы увеличиваете счетчик для каждого вызова до updateStatus и уменьшаете его в функции ответа на запрос AJAX (зависит от используемой библиотеки AJAX JavaScript).

Когда счетчик достигает нуля, все запросы AJAX завершены, и вы можете вызвать hideLoader () .

Вот пример:

var loadCounter = 0;

function updateStatuses(){
    updateStatus('cron1'); //performs an ajax request to get the status of something
    updateStatus('cron2');
    updateStatus('cron3');    
    updateStatus('cronEmail');
    updateStatus('cronHourly');
    updateStatus('cronDaily');
}

function updateStatus(what) {
    loadCounter++;

    //perform your AJAX call and set the response method to updateStatusCompleted()
}

function updateStatusCompleted() {
    loadCounter--;
    if (loadCounter <= 0)
        hideLoader(); //hide the 'loader.gif' in the UI
}
5
ответ дан 29 November 2019 в 23:23
поделиться

Это не имеет ничего общего с порядком выполнения кода.

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

Вы можете использовать тайм-аут после установки изображения, давая браузеру возможность обновить пользовательский интерфейс перед запуском остальной части кода:

function updateStatuses(){

  showLoader() //show the 'loader.gif' in the UI

  // start a timeout that will start the rest of the code after the UI updates
  window.setTimeout(function(){
    updateStatus('cron1'); //performs an ajax request to get the status of something
    updateStatus('cron2');
    updateStatus('cron3');
    updateStatus('cronEmail');
    updateStatus('cronHourly');
    updateStatus('cronDaily');

    hideLoader(); //hide the 'loader.gif' in the UI
  },0);
}

Есть еще один фактор, который также может заставить ваш код работать не в порядке. Если ваши запросы AJAX асинхронны, функция не будет ждать ответов. Функция, отвечающая за ответ, будет запущена, когда браузер получит ответ. Если вы хотите скрыть изображение загрузчика после получения ответа, вам придется сделать это при запуске последней функции обработчика ответа. Поскольку ответы не должны приходить в том порядке, в котором вы отправляли запросы, вам нужно будет подсчитать, сколько ответов вы должны знать, когда придет последний.

2
ответ дан 29 November 2019 в 23:23
поделиться

переместить вызовы updateStatus в другую функцию. сделайте вызов setTimeout с новой функцией в качестве цели.

Если ваши запросы ajax асинхронны, у вас должно быть что-то для отслеживания того, какие из них были выполнены. каждый метод обратного вызова может установить где-нибудь для себя флаг «завершено» и проверить, не сделал ли он это последним. если это так, то пусть он вызовет hideLoader.

0
ответ дан 29 November 2019 в 23:23
поделиться

Проблема возникает из-за того, что AJAX по своей природе асинхронный. Это означает, что вызовы updateStatus () действительно выполняются по порядку, но немедленно возвращаются, и интерпретатор JS достигает hideLoader () до того, как какие-либо данные будут получены из запросов AJAX.

Вы должны выполнить hideLoader () для события, когда вызовы AJAX завершены.

15
ответ дан 29 November 2019 в 23:23
поделиться

Установите Firebug, затем добавьте такую ​​строку в каждый из showLoader, updateStatus и hideLoader:

Console.log("event logged");

Вы см. перечисленные в окне консоли вызовы вашей функции, и они будут в порядке. Вопрос в том, что делает ваш метод updateStatus?

Предположительно, он запускает фоновую задачу, а затем возвращает ее, поэтому вы достигнете вызова hideLoader до завершения любой из фоновых задач. В вашей библиотеке Ajax, вероятно, есть обратный вызов OnComplete или OnFinished - вызовите оттуда следующий updateStatus.

1
ответ дан 29 November 2019 в 23:23
поделиться

Вы должны думать о JavaScript как о событиях, а не о процедурах, если вы занимаетесь программированием AJAX. Вы должны дождаться завершения первого вызова, прежде чем выполнять второй. Способ сделать это - привязать второй вызов к обратному вызову, который срабатывает по завершении первого. Не зная больше о внутренней работе вашей библиотеки AJAX (надеюсь, вы используете библиотеку), я не могу сказать вам, как это сделать, но, вероятно, это будет выглядеть примерно так:

showLoader();

  updateStatus('cron1', function() {
    updateStatus('cron2', function() {
      updateStatus('cron3', function() {
        updateStatus('cronEmail', function() {
          updateStatus('cronHourly', function() {
            updateStatus('cronDaily', funciton() { hideLoader(); })
          })
        })
      })
    })
  })
});

Идея такова: updateStatus принимает свой обычный аргумент, а также функцию обратного вызова, выполняемую по завершении. Довольно распространенный шаблон - передать функцию для запуска onComplete в функцию, которая предоставляет такую ​​ловушку.

Обновление

Если вы используете jQuery, вы можете прочитать о $. Ajax () здесь: http://api.jquery.com/jQuery.ajax/

Ваш код, вероятно, выглядит примерно так:

function updateStatus(arg) {
  // processing

  $.ajax({
     data : /* something */,
     url  : /* something */
  });

  // processing
}

Вы можете изменить свои функции, чтобы они принимали обратный вызов в качестве второго параметра, примерно так:

function updateStatus(arg, onComplete) {
  $.ajax({
    data : /* something */,
    url  : /* something */,
    complete : onComplete // called when AJAX transaction finishes
  });

}

14
ответ дан 29 November 2019 в 23:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: