Как JavaScript обрабатывает ответы AJAX в фоновом режиме?

Поскольку JavaScript выполняется в одном потоке, после выполнения запроса AJAX, что на самом деле происходит в фоновом режиме? Я хотел бы получить более глубокое понимание этого, может кто-нибудь пролить свет?

2 ответа

Решение

Под обложками у javascript есть очередь событий. Каждый раз, когда завершается поток выполнения javascript, он проверяет, есть ли еще одно событие в очереди для обработки. Если он есть, он вытаскивает его из очереди и запускает это событие (например, щелчок мышью).

Сеть с собственным кодом, которая находится под вызовом ajax, будет знать, когда будет выполнен ответ ajax, и событие будет добавлено в очередь событий javascript. То, как нативный код знает, когда выполняется вызов ajax, зависит от реализации. Он может быть реализован с помощью потоков или также может быть сам по себе событием (это не имеет значения). Суть реализации заключается в том, что когда ответ ajax сделан, некоторый нативный код узнает, что он сделан, и поместит событие в очередь JS.

Если в данный момент Javascript не запущен, событие будет немедленно запущено, что запустит обработчик ответа ajax. Если что-то выполняется в то время, то событие будет обработано, когда закончится текущий поток выполнения javascript. Там не должно быть никакого опроса с помощью движка JavaScript. Когда выполнение части Javascript завершается, механизм JS просто проверяет очередь событий, чтобы узнать, нужно ли что-либо еще запускать. Если это так, он выталкивает следующее событие из очереди и выполняет его (вызывая одну или несколько функций обратного вызова, которые зарегистрированы для этого события). Если в очереди событий ничего нет, то у интерпретатора JS есть свободное время (сборка мусора или ожидание), пока какой-либо внешний агент не поместит что-то еще в очередь событий и не разбудит его снова.

Поскольку все внешние события проходят через очередь событий, и ни одно событие не запускается, пока javascript фактически выполняет что-то еще, он остается однопоточным.

Вот несколько статей о деталях:

Вы можете найти здесь очень полную документацию по обработке событий в javascript.
Он написан парнем, работающим над реализацией javascript в браузере Opera.

Точнее, посмотрите на заголовки: "Поток событий", "Очередь событий" и "Непользовательские события": вы узнаете, что:

  1. Javascript запускается в одном потоке для каждой вкладки или окна браузера.
  2. События ставятся в очередь и выполняются последовательно.
  3. XMLHttpRequest запускается реализацией, а обратные вызовы запускаются с использованием очереди событий.

Примечание. Исходная ссылка была: ссылка, но теперь она не работает.

Я хочу немного подробнее рассказать о реализации ajax, упомянутой в ответах.

Хотя (обычное) выполнение Javascript не является многопоточным - как хорошо отмечено в приведенных выше ответах - однако реальная обработка AJAX responses (а также обработка запросов) не является Javascript, и он - обычно - многопоточный. (см. реализацию исходного кода хрома XMLHttpRequest, о которой мы поговорим выше)

и я объясню, давайте возьмем следующий код:

var xhr = new XMLHttpRequest();

var t = Date.now;
xhr.open( "GET", "https://swx.cdn.skype.com/shared/v/1.2.15/SkypeBootstrap.min.js?v="+t(), true );

xhr.onload = function( e ) {
  console.log(t() + ': step 3');
    
    alert(this.response.substr(0,20));
};
console.log(t() + ': step 1');
xhr.send();
console.log(t() + ': step 2');

after an AJAX request is made (- после шага 1), затем, пока ваш js-код продолжает выполняться (шаг 2 и после), браузер начинает реальную работу по: 1. форматированию tcp-запроса 2. открытию сокета 3. отправке заголовков 4. рукопожатию 5. отправке тело 6. ожидающий ответ 7. чтение заголовков 8. чтение тела и т. д. Вся эта реализация обычно выполняется в другом потоке параллельно с выполнением вашего кода js. Например, в упомянутой реализации Chromium используется Threadable Loader, перейдите на Digg- In (вы также можете получить некоторое впечатление, посмотрев вкладку "Сеть" загрузки страницы, вы увидите несколько одновременных запросов).

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

Другие вопросы по тегам