Что такое тик цикла событий Node.js?


84

Я все больше вникаю во внутреннее устройство архитектуры Node.js, и термин, который я часто вижу, - это «тик», как «следующий тик цикла событий» или функция nextTick () .

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

Могу ли я получить точное и подробное описание тика цикла событий Node.js?


так как его "цикл", это означает "в следующий раз, когда он зациклится", поэтому отметьте галочкой весь цикл, он заканчивается, когда никакие события не запускаются, а nodejs зацикливает все, чтобы проверить, запущено ли какое-либо, "nextTick" это означает следующий цикл после текущего.
Gntem 06

Ответы:


156

Помните, что хотя JavaScript является однопоточным, весь ввод-вывод узла и вызовы собственных API-интерфейсов либо асинхронны (с использованием механизмов, зависящих от платформы), либо выполняются в отдельном потоке. (Все это делается через libuv.)

Поэтому, когда в сокете доступны данные или возвращается собственная функция API, нам нужен синхронизированный способ вызова функции JavaScript, которая заинтересована в конкретном событии, которое только что произошло.

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

Итак, что мы делаем, так это помещаем событие в очередь потокобезопасным способом. В упрощенном псевдокоде это примерно так:

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, чтобы синхронные вызовы библиотеки C / C ++ выглядели асинхронными

2
Да, вы это прибили. Копирование очереди и просмотр всех событий в копии было тем, что меня особенно интересовало. Хотя теперь это имеет большой смысл. Благодарю.
d512 07

Это знаменитый алгоритм «асинхронного итерационного шаблона»?
Стеф

1
@sanjeev, что вы подразумеваете под "постоянной работой"? Единственное, что делает текущее приложение JavaScript, - это обрабатывает события.
josh3736

2
Я хотел бы добавить, что в 0.10.x setImmediateтакже будет добавлена ​​функция.
DanielKhan

1
Означает ли галочка фазу цикла событий?
faressoft

10

Более простой ответ для новичков в JavaScript:

Первое, что нужно понять, это то, что JavaScript - это «однопоточная среда». Это относится к поведению JavaScript при выполнении ваших блоков кода по одному из «цикла событий» в одном потоке. Ниже представлена ​​простая реализация цикла событий, взятая из книги Кайла Симпсона ydkJS, а затем объяснение:

// `eventLoop` is an array that acts as a queue (first-in, first-out)
var eventLoop = [ ];
var event;

// keep going "forever"
while (true) {
    // perform a "tick"
    if (eventLoop.length > 0) {
        // get the next event in the queue
        event = eventLoop.shift();

        // now, execute the next event
        try {
            event();
        }
        catch (err) {
            reportError(err);
        }
    }
}

Первый цикл while имитирует цикл событий. Тик - это исключение события из «очереди цикла событий» и выполнение указанного события.

См. Ответ «Josh3796» для более подробного объяснения того, что происходит при удалении из очереди и выполнении события.

Также я рекомендую прочитать книгу Кайла Симпсона тем, кто заинтересован в глубоком понимании JavaScript. Он полностью бесплатный и с открытым исходным кодом, его можно найти по этой ссылке: https://github.com/getify/You-Dont-Know-JS.

Конкретный раздел, на который я ссылался, можно найти здесь: https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/sync-async/ch1.md


1

Очень простой и короткий способ установки тика Event Loop:

Он используется внутренним механизмом узла, где при обработке набора запросов в очереди запускается тик, который представляет собой завершение задачи.


не могли бы вы предоставить какой-нибудь источник вашего ответа?
Кик Бутовски
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.