Я думаю об этом, и вот что я придумал:
Посмотрим на этот код ниже:
console.clear();
console.log("a");
setTimeout(function(){console.log("b");},1000);
console.log("c");
setTimeout(function(){console.log("d");},0);
Приходит запрос, и JS-движок начинает шаг за шагом выполнять приведенный выше код. Первые два вызова - это вызовы синхронизации. Но когда дело доходит до setTimeout
метода, он становится асинхронным. Но JS немедленно возвращается из него и продолжает выполнение, которое называется Non-Blocking
или Async
. И он продолжает работать над другими и т. Д.
Результаты этого исполнения следующие:
AcDb
Таким образом, в основном вторая setTimeout
завершается первой, и ее функция обратного вызова выполняется раньше, чем первая, и это имеет смысл.
Здесь мы говорим об однопоточном приложении. JS Engine продолжает выполнять это, и если он не завершит первый запрос, он не перейдет ко второму. Но хорошо то, что он не будет ждать, пока блокирующие операции, например, setTimeout
разрешатся, поэтому он будет быстрее, потому что он принимает новые входящие запросы.
Но мои вопросы возникают по следующим пунктам:
№1: Если мы говорим об однопоточном приложении, то какой механизм обрабатывает, в setTimeouts
то время как JS-движок принимает больше запросов и выполняет их? Как отдельный поток продолжает работать над другими запросами? Что работает, в setTimeout
то время как другие запросы продолжают поступать и выполняться.
# 2: Если эти setTimeout
функции выполняются за кулисами, в то время как поступает и выполняется больше запросов, что за кулисами выполняет асинхронное выполнение? Что это за вещь, о которой мы говорим, называется EventLoop
?
# 3: Но не следует ли поместить весь метод в EventLoop
так, чтобы все это выполнялось и вызывается метод обратного вызова? Вот что я понимаю, когда говорю о функциях обратного вызова:
function downloadFile(filePath, callback)
{
blah.downloadFile(filePath);
callback();
}
Но в этом случае, как JS Engine узнает, является ли это асинхронной функцией, чтобы он мог поместить обратный вызов в EventLoop
? Возможно, что-то вроде async
ключевого слова в C # или какого-то атрибута, который указывает, что метод, который будет использовать JS Engine, является асинхронным и должен обрабатываться соответствующим образом.
# 4: Но в статье говорится совершенно противоположное тому, что я предполагал о том, как все может работать:
Цикл событий - это очередь функций обратного вызова. Когда выполняется асинхронная функция, функция обратного вызова помещается в очередь. Механизм JavaScript не начинает обработку цикла событий, пока не будет выполнен код после выполнения асинхронной функции.
# 5: И вот это изображение, которое может быть полезно, но первое объяснение на изображении говорит то же самое, что упоминалось в вопросе номер 4:
Итак, мой вопрос заключается в том, чтобы получить некоторые пояснения по перечисленным выше пунктам?
Ответы:
В процессе узла есть только 1 поток, который фактически выполняет JavaScript вашей программы. Однако в самом узле на самом деле существует несколько потоков, обрабатывающих операцию механизма цикла событий, и это включает пул потоков ввода-вывода и несколько других. Ключ в том, что количество этих потоков не соответствует количеству обрабатываемых одновременных подключений, как это было бы в модели параллелизма «поток на подключение».
Теперь о «выполнении setTimeouts», когда вы вызываете
setTimeout
, все, что делает узел, это в основном обновляет структуру данных функций, которые будут выполняться одновременно в будущем. По сути, у него есть куча очередей вещей, которые нужно сделать, и каждый «тик» цикла событий он выбирает один, удаляет его из очереди и запускает.Ключевым моментом является понимание того, что большую часть тяжелой работы узел полагается на ОС. Таким образом, входящие сетевые запросы фактически отслеживаются самой ОС, и когда узел готов обработать один, он просто использует системный вызов, чтобы запросить у ОС сетевой запрос с данными, готовыми к обработке. Так большая часть "работы" узла ввода-вывода - это либо "Эй, ОС, есть ли сетевое соединение с данными, готовыми к чтению?" или «Привет, ОС, у любого из моих невыполненных вызовов файловой системы есть данные?». Основываясь на своем внутреннем алгоритме и конструкции механизма цикла событий, узел выберет один «тик» JavaScript для выполнения, запустит его, а затем повторит процесс заново. Вот что подразумевается под циклом событий. По сути, Node всегда определяет, «какой следующий кусочек JavaScript мне следует запустить?», А затем запускает его.
setTimeout
илиprocess.nextTick
.Никакой JavaScript не выполняется за кулисами. Весь JavaScript в вашей программе запускается впереди и по центру, по одному. За кулисами происходит то, что операционная система обрабатывает ввод-вывод, и узел ожидает его готовности, а узел управляет своей очередью javascript, ожидающих выполнения.
В ядре узла есть фиксированный набор функций, которые являются асинхронными, потому что они выполняют системные вызовы, и узел знает, какие это, потому что они должны вызывать ОС или C ++. В основном все операции ввода-вывода в сети и файловой системе, а также взаимодействия с дочерними процессами будут асинхронными, и ЕДИНСТВЕННЫЙ способ, которым JavaScript может заставить узел запускать что-то асинхронно, - это вызвать одну из асинхронных функций, предоставляемых базовой библиотекой узла. Даже если вы используете пакет npm, который определяет свой собственный API, чтобы создать цикл событий, в конечном итоге этот код пакета npm вызовет одну из асинхронных функций ядра узла, и когда узел узнает, что тик завершен, и он может запустить событие алгоритм цикла снова.
Да, это правда, но это заблуждение. Ключевым моментом является то, что нормальный паттерн:
Итак, да, вы можете полностью заблокировать цикл событий, просто подсчитывая числа Фибоначчи синхронно в памяти и за один тик, и да, это полностью остановит вашу программу. Это кооперативный параллелизм. Каждый тик JavaScript должен приводить к возникновению цикла событий в течение некоторого разумного периода времени, иначе архитектура в целом выйдет из строя.
источник
process.nextTick
vssetTimeout
vssetImmediate
немного отличается, хотя вам не о чем беспокоиться. У меня есть сообщение в блоге под названием setTimeout и друзья , в котором рассказывается более подробно.Филип Робертс подготовил фантастический видеоурок, который объясняет цикл событий javascript самым упрощенным и концептуальным образом. Каждый разработчик javascript должен посмотреть.
Вот ссылка на видео на Youtube.
источник
Не думайте, что хост-процесс является однопоточным, это не так. Однопоточным является часть хост-процесса, выполняющая ваш код javascript.
За исключением фоновых рабочих , но они усложняют сценарий ...
Итак, весь ваш js-код выполняется в одном потоке, и нет возможности, что вы получите две разные части вашего js-кода для одновременного запуска (так что вам не придется управлять параллелизмом).
Выполняемый js-код - это последний код, который хост-процесс получил из цикла событий. В своем коде вы можете в основном делать две вещи: запускать синхронные инструкции и планировать функции, которые будут выполняться в будущем, когда произойдут какие-то события.
Вот мое мысленное представление (осторожно: просто я не знаю деталей реализации браузера!) Вашего примера кода:
Пока ваш код выполняется, другой поток в хост-процессе отслеживает все происходящие системные события (щелчки пользовательского интерфейса, чтение файлов, полученные сетевые пакеты и т. Д.)
Когда ваш код завершается, он удаляется из цикла событий, и хост-процесс возвращается к его проверке, чтобы увидеть, есть ли еще код для запуска. Цикл событий содержит еще два обработчика событий: один должен быть выполнен сейчас (функция justNow), а другой - в течение секунды (функция inAWhile).
Теперь хост-процесс пытается сопоставить все произошедшие события, чтобы увидеть, зарегистрированы ли для них обработчики. Он обнаружил, что событие, которого ожидает justNow, произошло, поэтому он начал запускать свой код. При выходе из функции justNow она проверяет цикл событий в другой раз, ища обработчики событий. Предположим, что прошла 1 с, запускается функция inAWhile и так далее ....
источник