Помните, что в то время как JavaScript является однопоточным, все операции ввода/вывода узла и вызовы на собственные API-интерфейсы либо асинхронны (с использованием механизмов, специфичных для платформы), либо работают в отдельном потоке. (Все это обрабатывается через libuv.)
Итак, когда в сокете имеются данные, доступные для функции API, нам нужен синхронизированный способ вызова функции JavaScript, которая интересуется конкретным событием, которое только что произошло.
Нельзя просто вызвать функцию JS из потока, в котором произошло родное событие по тем же причинам, с которыми вы столкнулись в регулярном многопоточном приложении – условия гонки, доступ к неатомам памяти и т. Д. ,
Так что мы делаем это событие в очереди в потокобезопасном режиме. В упрощенно psuedocode, что-то вроде:
lock (queue) {
queue.push(event);
}
Затем обратно на основной JavaScript нить (но на стороне C вещей), мы делаем что-то вроде:
while (true) {
// this is the beginning of a tick
lock (queue) {
var tickEvents = copy(queue); // copy the current queue items into thread-local memory
queue.empty(); // ..and empty out the shared queue
}
for (var i = 0; i < tickEvents.length; i++) {
InvokeJSFunction(tickEvents[i]);
}
// this the end of the tick
}
while (true)
(который на самом деле не существует в исходном коде узла, это просто иллюстративно) представляет цикл событий . Внутренний for
вызывает функцию JS для каждого события, которое находилось в очереди.
Это галочка: синхронный вызов нулевой или более функций обратного вызова, связанных с любыми внешними событиями. Как только очередь будет опустошена и последняя функция вернется, галочка завершена. Мы возвращаемся к началу (следующий тик) и проверяем события, которые были добавлены в очередь из других потоков , пока наш JavaScript работал.
Что может добавить вещи в очередь?
process.nextTick
setTimeout
/setInterval
- ввода/вывода (материал от
fs
, net
, и так далее)
crypto
«ы ресурсоемких функций, таких как криптографических потоков, PBKDF2, и PRNG (которые на самом деле являются примером ...)
- любые родные модули, использующие libuv work queue сделать синхронное C/библиотека C++ вызовы выглядят асинхронные
, так как его «петля», это означает, что «в следующий раз, когда он закругляется», так что отметьте его целым циклом, он заканчивается, когда никакие события не запускаются, а nodejs зацикливает все, чтобы проверить, запущен ли какой-либо из них, «nextTick» означает следующий цикл после текущего. – Gntem