2015-04-30 5 views
4

Я читаю о циклах событий в node.js. В соответствии с моим просмотром различных статей и сообщений в stackexchange я получил , все обратные вызовы добавляются в конце очереди задач, а после выполнения основного файла все задачи в очереди выполняются последовательно. Я попытался подтвердить это небольшой программой. Там я обнаружил странное поведение. Ниже приведено содержимое файла main.js, который я создал.Разница в поведении node.js Цикл событий для встроенных и настраиваемых событий

//Declare file open event handler 
var fs = require("fs"); 
var ws = fs.createWriteStream("C:\\test.txt"); 
ws.on("open", function(fd) { 
    console.log("#Event file 'open'"); 
}); 

//Wait for 5 seconds 
var startTime = new Date().getTime(); 
console.log("Give time of 5 seconds to get file opened (being conservative)...\n"); 
while(new Date().getTime() - startTime < 5000) {} 

//Create custom event 
var util = require("util"); 
var EventEmitter = require("events").EventEmitter; 
var CustomEventEmitter = function() {}; 
util.inherits(CustomEventEmitter, EventEmitter); 

//Declare custom event handler 
var customInstance = new CustomEventEmitter(); 
customInstance.on("tick", function() { 
    console.log("#Event custom 'tick'"); 
}); 

//Emit custom event 
customInstance.emit("tick"); 

console.log("#End 'main.js'"); 

Он дал мне следующий вывод:

Give time of 5 seconds to get file opened (being conservative)... 

#Event custom 'tick' 
#End 'main.js' 
#Event file 'open' 

Журнал "#Event файл" открытым" выводится после того, как "#End 'main.js'", но как же журнал" #Event custom 'tick' "пришел первым, если он должен был находиться в очереди задач.

Я имею в виду, как встроенное событие показывает правильное поведение, а пользовательское событие - нет?

Пожалуйста, исправьте мое понимание об этом :)

ответ

4

Главное, что emitter.emit() является синхронным.

Вот что происходит, шаг за шагом:

  • При вызове fs.createWriteStream(), что вызывает функцию асинхронной которая получает положить в очереди задач для обработки после того, как текущий тик закончится.

  • Затем ваша петля while происходит в течение пяти секунд, что не влияет на порядок срабатывания событий, как мы увидим.

  • Далее вы излучаете свое событие tick. Круто.emit() синхронно и увольняет слушатель, так: #Event заказного тик »входит здесь

  • Ваша главная функция заканчивается. #End 'main.js' журналы здесь. .

  • узла принимает функцию (которая была помещена в очереди задач по createWriteStream() из очереди заданий Это в конечном итоге приводит к стрельбе событий open, в результате: #Event файла «открытый» регистрирует здесь

Так вот почему вещи появляются в таком порядке.

+0

hmm ... У меня было именно это на мой взгляд, и в соответствии с этим пониманием порядок вывода должен был быть таким: #End 'main.js' #Event file 'open' #Event custom 'tick' ...... main.js должен был быть первой строкой, и пользовательский тик должен был быть последним ... исправьте меня, если я ошибаюсь ... –

+0

О, я пропустил это 'emit()' не является асинхронным. Обновлено. Полагаю, теперь это правильно объясняет ваш результат. – Trott

+0

Спасибо, наконец, получил это ... Вы правы, это потому, что функция испускания является синхронной ([link] (https://github.com/iojs/io.js/blob/10e31ba56c676bdcad39ccad22ea9117733b8eb5/lib/events.js # L67)), и поэтому обработчик события называется синхронно. Он не помещает функцию обработчика в очередь событий ... –

0

когда вы пересекать время цикла, как вы делали, вы в основном угнать нить и привязывают процессор в течение 5 секунд. Попробуйте выполнить те же тесты с помощью setInterval или setTimeout. SetTimeout/Interval позволяет js-движку выполнять другие задачи между циклами. Даже если вы дадите ему 1 мс в качестве пробела, этого достаточно, чтобы двигатель очистил свою очередь.

(Дальнейшее уточнение - редактирование)

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

В случае вашего пользовательского события это не было асинхронным, поэтому на самом деле он ведет себя так же странно, как ваш счетчик. Поток продолжал выполнять инструкции последовательно из-за характера CustomEventEmitter. Вы увидите это в событиях jQuery click в браузере. Это синхронно, поэтому все инструкции обработчика событий впереди в цикле событий.

Так зная, что что-то выполняет async или нет, это поможет понять смысл потока js-кода. Цикл while и CustomEventEmitter являются одновременно синхронными операциями, а fs - асинхронными.

Надеюсь, это уточнит.

+0

Я ценю ваши усилия ... но я искал причину заказа журнала событий, чтобы понять петлю лучше. Я знаю, setInterval и SetTimeout будет работать отлично, но для этой программы, как я понимаю nding, выходным журналом должно быть: #End 'main.js' #Event file 'open' #Event custom 'tick' ...., который не отображается. –

+1

Ну, я видел, что вы хотели «дать 5 секунд, чтобы открыть файл». Я хотел удостовериться, что вы знали, что движок js мог бы делать ничего, кроме этого, пока цикл был запущен. Это на самом деле полностью объясняет, в то время как самый быстрый разрыв в цикле событий был после #End. Все эти утверждения были в первом цикле, поэтому открытие должно было произойти потом. –

+0

вы правы, Рон, открытый порядок регистрации в порядке, это как и ожидалось. Но я задаюсь вопросом о журнале регистрации пользовательских тиков. Почему это на первом месте? Это должно было быть где-то после #End, а не раньше #End ... –

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