Что происходит в JavaScript, когда AJAX-вызов возвращается во время выполнения скрипта? - PullRequest
38 голосов
/ 12 июля 2011

Предположим, я пишу некоторый JavaScript, который выполняет вызов AJAX с myCallback в качестве метода обратного вызова, который выполняется при успешном выполнении AJAX.

Предположим, что какой-то другой метод JavaScript с именем myFunction вызывается на моей странице, когда myCallback вызывается асинхронно.

Имеет ли одна операция приоритет над другой? Они оба бегут одновременно? Что происходит?

Ответы [ 8 ]

56 голосов
/ 12 июля 2011

Предположим, что какой-то другой метод 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, который, в свою очередь, вызывает обработчики событий, изатем возвращается, ничем не отличаясь от того, что вы вызываете своими собственными функциями.) Ключевым моментом, который имеет общий элемент, на который указывает Боб, является то, что ваш код вызвал что-то в среде хоста, которая уходит и делает что-то (показывает модальное диалоговое окно,пожары blur и focus, обработчики и т.в пользу более современных методов (которые также могут выглядеть примерно в 18 раз лучше).

Так что это предостережения, упомянутые в начале ответа.И, в частности, если myFunction вызывает alert, по крайней мере в Firefox обратный вызов завершения ajax будет запускаться во время alert (не будет в большинстве других браузеров).Если вам интересно узнать, что происходит, а что не происходит во время alerts и т. Д., , вот тестовая страница , проверяющая setTimeout и ajax;Вы можете расширить тесты, чтобы пойти дальше.

7 голосов
/ 12 июля 2011

Все эти ответы неверны [править: не менее 3-4 неправильных, когда этот ответ был опубликован]. Событие XHR помещается в очередь / пул событий. Когда однопоточный поток JavaScript не занят, он будет извлекать следующие события из пула событий и воздействовать на них. Одним из таких событий будет ваш XHR-запрос «AJAX», который вызовет обратный вызов, который затем будет выполнен. Так работают все управляемые событиями системы без прерываний.

edit : Upvoting ответ Джо, который ссылается на Гарантируется ли JavaScript однопоточным? и упоминаются тонкие крайние случаи. Очень информативно.

3 голосов
/ 12 июля 2011

Вид Javascript однопоточный см. Гарантируется ли JavaScript однопоточным? . Таким образом, ответ НЕТ, ваш обработчик событий и ваша функция могут работать одновременно, а могут и нет.

2 голосов
/ 12 июля 2011

Обратный вызов AJAX выполняется в следующем цикле событий.

0 голосов
/ 12 июля 2011

AJAX-вызовы являются «асинхронными», что означает «отключить вызов и дать мне знать, что вы хотите, чтобы я перезвонил, когда я это сделаю».

вкратце:

function DoSomething() { AJAXCall(Callback); }

 ... some time passes then ...

function Callback() { Done(); }

Между этими двумя вызовами функций может произойти все что угодно, обратный вызов все равно будет вызываться при возврате ответа, потому что, хотя среда выполнения javascript является однопоточной, браузер будет составлять вызовы в некотором порядке (вероятно, в порядке, в котором они сделаны, но негарантировано).

Жаль, что я только что вытащил свой старый веб-сайт, потому что у меня был классический пример того, как страница выполняла несколько вызовов ajax при загрузке, так как каждый возвращенный вызов заполнял различные части страницы.

, хотя каждый вызов был «присоединен» к событию загрузки документа, только один вызов мог быть выполнен за раз, но сервер мог ответить на любой вызов в любом порядке, потому что сервер мог быть многопоточным (и, скорее всего, есть).

Думайте о javascript как о виртуальной коробке, в которой браузер может передавать небольшой кусок кода, онможет запускать только 1 комок за раз, но он может запускать множество сценариев в любом порядке, который он сочтет нужным (обычно это непредсказуемо при множественных вызовах ajax, потому что кто знает, когда сервер может вернуться с результатом)

0 голосов
/ 12 июля 2011

Когда ajax завершается успешно и вызывает myCallback, он будет работать синхронно.Таким образом, myCallback похож на другие функции: вы вызываете его первым, он запускается первым, или вы вызываете его последним, он запускается последним.ОНИ НЕ БУДУТ РАБОТАТЬ В ТО ЖЕ ВРЕМЯ.

0 голосов
/ 12 июля 2011

Вы можете быстро проверить это, поместив предупреждение («первый»);оповещение («второй»);в обеих функциях, и посмотрите, какое модальное всплывающее окно появляется первым.Если порядок действительно влияет на ваш код, поместите несколько условных проверок, чтобы предотвратить / разрешить что-либо.Скорость нативного js по сравнению со скоростью полного туда-обратно и с сервера сильно отличается.Если у вас не работает какой-либо javascript в бесконечном цикле, шансы вызова ajax, возвращаемого во время выполнения вашей другой функции, ничтожны.

0 голосов
/ 12 июля 2011

Аякс звонит с быть одновременно.Поэтому, когда вызов ajax успешен, вызывается функция обратного вызова, которая, в свою очередь, вызывает функцию myfunction.

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