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

84

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

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

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

d512
источник
так как его "цикл", это означает "в следующий раз, когда он зациклится", поэтому отметьте галочкой весь цикл, он заканчивается, когда никакие события не запускаются, а 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 ++ выглядели асинхронными
josh3736
источник
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:

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

Акс
источник
не могли бы вы предоставить какой-нибудь источник вашего ответа?
Кик Бутовски