2013-11-06 5 views
50

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

То, что я еще не видел, является прочным определением того, что такое «тик». Основываясь на разных статьях (such as this one), мне удалось скомпоновать концепцию вместе с моей головой, но я не уверен, насколько она точна.

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

+0

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

ответ

103

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

+1 для отличного ответа! –

+2

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

+0

Является ли это знаменитым «Асинхронным итерационным шаблоном»? – Stef

1

Более простой ответ для тех, кто новичок в 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); 
     } 
    } 
} 

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

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

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

Конкретный раздел I ссылки можно найти здесь: https://github.com/getify/You-Dont-Know-JS/blob/master/async%20%26%20performance/ch1.md#event-loop

Смежные вопросы