Подтвердить что ты не робот

Что происходит в JavaScript, когда вызов AJAX возвращается при выполнении script?

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

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

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

4b9b3361

Ответ 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; вы можете расширить тесты, чтобы продолжить.

Ответ 2

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

изменить. Активировать ответ Джо, который ссылается на Является ли JavaScript гарантированным однопоточным? и упоминает тонкие краевые случаи. Очень информативно.

Ответ 4

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

так короче:

function DoSomething() { AJAXCall(Callback); }

 ... some time passes then ...

function Callback() { Done(); }

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

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

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

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

Ответ 8

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