Ответ 1
Предположим, что какой-либо другой метод JavaScript, называемый
myFunction
, вызывается на моей странице, когдаmyCallback
вызывается асинхронно.Выполняется ли одна операция над другой? Они оба работают одновременно? Что происходит?
JavaScript в браузерах однопоточен (запрет использования веб-работников, а синтаксис для этого явно). Таким образом, myFunction
будет работать до тех пор, пока не вернется — с некоторыми предостережениями (продолжайте читать). Если уровень ajax завершает операцию, когда выполняется myFunction
(что очень хорошо), и ему необходимо вызвать обратный вызов, этот вызов становится в очереди. В следующий раз, когда ваш код выйдет, будет запущен следующий вызов в очереди.
Может показаться, что нам никогда не придется беспокоиться о гоночных условиях. Это в основном верно, но есть тонкости. Например, рассмотрите этот код:
var img = document.createElement('img');
img.src = /* ...the URL of the image... */;
img.onload = function() {
// Handle the fact the image loaded
foo();
};
doSomethingElse();
doYetAnotherThing();
Поскольку JavaScript в браузерах однопоточен, я гарантированно получаю событие load
, когда изображение загружается, правильно?
Неправильно.
Код JavaScript является однопоточным, но остальная часть среды, вероятно, отсутствует. Поэтому может случиться так, что, установив img.src
, браузер может увидеть, что у него есть кешированная копия изображения, которое он может использовать, и поэтому он запускает событие load
на img
между строкой img.src = ...
и строку img.onload = ...
. Поскольку мой обработчик еще не подключен, я не получаю вызов, потому что к моменту присоединения моего обработчика событие уже запущено.
Но вы можете увидеть эффект очереди, если мы отменим эти строки:
var img = document.createElement('img');
img.onload = function() {
// Handle the fact the image loaded
foo();
};
img.src = /* ...the URL of the image... */;
doSomethingElse();
doYetAnotherThing();
Теперь я подключаю событие до установки src
. Если событие срабатывает между строкой img.src = ...
и строкой doSomethingElse
(поскольку браузер имеет изображение в кеше), обратный вызов к моему обработчику попадает в очередь. doSomethingElse
и doYetAnotherThing
выполняются до выполнения моего обработчика. Только когда управление выходит из моего кода, очередь на вызов моего обработчика, наконец, запускается. Код JavaScript является однопоточным, но среда не является.
Вы также можете отказаться от среды хоста неочевидными способами. Например, вызывая alert
или его дыхание confirm
, prompt
и т.д. Эти функции торчат, как больные превью, которые они находятся в современном JavaScript, потому что они не управляются событиями; вместо этого выполнение JavaScript приостанавливается, пока отображается модальное окно. Но поскольку bobince указывает на его углубленное обсуждение здесь, это не значит, что ни один из ваш другой код будет работать во время показа модальности. Он по-прежнему однопоточный, но один поток приостанавливается в одном месте (модальным) и используется для запуска кода в другом месте в то же время; действительно очень тонкое различие. (Боб также указывает на некоторую обработку событий > его пример focus
— это, похоже, нарушает это правило, но это не так. В его примере вызывается focus
, который, в свою очередь, вызывает обработчики событий, а затем возвращает, ничем не отличающийся от того, как вы вызываете свои собственные функции.) Главное, что указывают пункты, которые Боб указывает на то, что ваш код вызвал что-то в среде хоста, которая уходит и что-то делает (показывает модальный диалог, t222 > и focus
и т.д.).
(alert
и его дыхание, в частности, вызывают всевозможные гадости, особенно вокруг focus
и blur
, и я рекомендую избегать их в пользу более современных методов (что также может выглядеть примерно в 18 раз).
Итак, это те предостережения, которые были упомянуты в начале ответа. И, в частности, если myFunction
вызывает alert
, по крайней мере на Firefox, обратный вызов завершения ajax будет запущен во время alert
(он не будет использоваться в большинстве других браузеров). Если вам интересно узнать, что происходит и чего не происходит во время alerts
и т.д., здесь тестовая страница, тестирующая setTimeout
и ajax; вы можете расширить тесты, чтобы продолжить.