Как работать с 2 XMLHttpRequest, зависящим от другого?

Я работаю над проектом, где у меня есть 2 объекта XMLHttpRequest(), например A и B.

То, что я хочу выполнить, - это когда A заканчивает получение списка элементов данных, B будет запущен для извлечения еще нескольких элементов на основе предыдущих выборок элементов данных A.

В настоящее время моя проблема заключается в том, что два объекта работают независимо друг от друга.

Мой код ниже:

            var A = new XMLHttpRequest();

            var B = new XMLHttpRequest();

            A.open("GET", directory, true);
            A.onreadystatechange = function () {

                if (A.readyState === 4) {
                    if (A.status === 200 || A.status == 0) {
                     //does... something
                     }
                }

            }
            A.send(null);
            while(true){

                B.open("GET", another_directory, false);
                B.overrideMimeType("application/document");
                B.send(null);
                if (B.status == "404")
                continue;

                 //does... something else
            }

Этот код не работает, потому что я нахожу, что Evertime B работает до завершения A. В основном я не знаю, какое событие использовать.

Как я могу выполнить свою задачу? Какие события я могу использовать, чтобы я мог синхронизировать обработку B сразу после окончания A?

Ответ 1

Итак, давайте начнем с вашего кода. Я добавил несколько комментариев к нему, поэтому теперь вы можете понять источник проблемы:

var A = new XMLHttpRequest(); //You create an XMLHttpRequest object
var B = new XMLHttpRequest(); //And an another

A.open("GET", directory, true); 

/* Now you open a GET request to DIRECTORY, with async TRUE. The third parameter can 
make a request sync or async, but sync is not recommended as described below. */

A.onreadystatechange = function () {
    if (A.readyState === 4) {
        if (A.status === 200 || A.status == 0) {

        /* So you registered an event listener. It runs when the readyState changes.
        You can use it to detect if the request is finished or not. If the readyState is
        4, then the request is finished, if the status code is 200, then the response is
        OK. Here you can do everythin you want after the request. */

         }
    }

}

A.send(null); //Now you send the request. When it finishes, the event handler will
// do the processing, but the execution won't stop here, it immediately goes to the 
// next function

while(true){ // Infinite loop
     B.open("GET", another_directory, false); //Open request B to ANOTHER_DIRECTORY,
     // but now, request B will be synchronous

     B.overrideMimeType("application/document"); // Configure mime type

     B.send(null); // Send the request

     if (B.status == "404")
         continue;
         // If it not found, then go to the next iteration

     // and do something else
}

Надеюсь, что теперь вы можете увидеть источник проблемы. Когда вы запустите этот script, тогда начните асинхронный запрос, а затем сразу же запустите следующий. Теперь вы можете выбрать один из двух способов.

Запустить следующий запрос от обратного вызова (рекомендуется)

Это лучший способ. Итак, начните свой первый (асинхронный) запрос, а в прослушивателе событий (где вы выполните обработку) вы можете запустить следующий запрос. Я привел здесь комментарий: http://jsfiddle.net/5pt6j1mo/1/

(Вы можете сделать это без массивов - это был всего лишь пример)

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

Синхронный AJAX (не рекомендуется)

Я не рекомендую его, потому что "Синхронный XMLHttpRequest в основном потоке устарел" в Chrome, но если вы действительно хотите, то можете попробовать использовать это решение. Таким образом, открытая функция XMLHttpRequest имеет 3 аргумента:

  • МЕТОД: какой HTTP-метод использовать
  • URL: какой URL-адрес запрашивать
  • ASYNC: асинхронный запрос? Если false, то это будет синхронно, что означает, что после вызова .send() он приостанавливает выполнение до тех пор, пока ответ не вернется.

Итак, если вы установите третий параметр в FALSE, вы можете легко это сделать... но вы не должны!

Ответ 2

Вот альтернативное решение, либо используйте API fetch, либо promisify native XHR и эта проблема становится намного проще:

fetch(directory).then(function(response){
    // some processing
    return fetch(another_directory); // can change content type too, see the mdn docs
}).then(function(responseTwo){
      // all processing is done
}).catch(function(err){
      // handle errors from all the steps above at once
});

Это так же естественно, как XHR, и гораздо проще управлять с помощью promises.

Ответ 3

(После продолжительного редактирования) я бы настоятельно рекомендовал, чтобы вы нашли время, чтобы понять природу асинхронных вызовов в JavaScript. Здесь немного рекомендуемого чтения. Асинхронное программирование в JavaScript Я думаю, это достаточно просто, чтобы понять, что происходит. Примечание. Остановите чтение в "Enter Mobl".

В JavaScript при вызове функции система помещает эту функцию в "очередь" с неявной инструкцией, чтобы идти вперед и запускать ее, как только сможете. Он делает это для каждого вызова функции. В вашем случае вы говорите системе, чтобы запустить A, затем запустите B. A идет в очередь, B переходит в очередь. Они представлены как индивидуальные функции. B запускается первым.

Для обычных функций, если вы хотите управлять последовательностью, вы можете вложить вызов функции A в вызов функции B. Но упс. Вы используете XMLHttpRequest, поэтому это ограничивает вашу способность настраивать функции. Читай дальше. Проверьте Шаблоны Ajax на тему Посмотрите на абзац для "Асинхронные вызовы". Посмотрите на свой код...

A.onreadystatechange = function () {
    if (A.readyState === 4) {
         if (A.status === 200 || A.status == 0) {
             //does... something
             (RUN ALL THE B.methods right here...)
         }
    }
}

Я думаю, что это приведет вас к месту назначения, если вы не хотите решения jQuery.

Для человека, который просто хочет работать с системой и не хочет лучше понимать язык, вот решение jquery... Обратите внимание, как вызов функции B вложен в вызов функции A. Обратите внимание, что порядок этого вложенности основан на наличии тэга успеха jQuery. Если вы не используете jQuery, вам придется вручную назначить функции.

var special_value;
$("button").click(function(){
    $.ajax({url: "demo_testA.html", 
            type: 'GET',
            success: function(resultA){
               special_value = resultA;
               $.ajax({url: "demo_testB.html",
                      type: 'GET', 
                      data: special_value, 
                      success: function(resultB){
                            $("#div1").html(resultB);
               }});
    });
});

Я скажу, что было бы намного проще помочь вам помочь себе в использовании лучших коммуникаций. Если вам что-то не нравится, тогда так заявляйте. Если вы не понимаете, что-то попросите дать больше разъяснений или отредактируйте выражение о проблеме. Обратная связь - это хорошо.