Новичок в node.js, какое преимущество дает обратный вызов по сравнению с событиями?

24

Я новичок в JavaScripter и не знаю, что происходит внутри движка V8.

Сказав это, я действительно наслаждаюсь своими ранними набегами в среду node.js, но я нахожу, что я постоянно использую events.EventEmitter () в качестве средства для генерации глобальных событий, чтобы я мог структурировать свои программы так, чтобы они соответствовали наблюдателю-уведомителю. шаблон похож на то, что я написал бы, скажем, в программе Objective-C или Python.

Я всегда делаю такие вещи:

var events = require('events');

var eventCenter = new events.EventEmitter();

eventCenter.on('init', function() {
    var greeting = 'Hello World!';
    console.log('We're in the init function!);
    eventCenter.emit('secondFunction', greeting);
});

eventCenter.on('secondFunction', function(greeting) {
        console.log('We're in the second function!);
        console.log(greeting);
    eventCenter.emit('nextFunction');
});

eventCenter.on('nextFunction', function {
    /* do stuff */
});

eventCenter.emit('init');

Так что, по сути, я просто структурирую код «async» node.js в код, который выполняет все в ожидаемом порядке, вместо этого я как бы «кодирую задом наперед», если это имеет смысл. Будет ли какая-то разница в том, чтобы делать это в режиме обратного вызова, либо с точки зрения производительности, либо с точки зрения философии? Что лучше сделать, используя обратные вызовы вместо событий?

бегать трусцой
источник
Если вы обнаружите, что читаемость вашего кода страдает из-за интенсивного использования обратных вызовов, рассмотрите возможность использования инфраструктуры, чтобы обернуть использование обратных вызовов. Это требует некоторой корректировки, но обещания часто могут распутать уродливые обратные вызовы. Если вы используете JQuery, вы можете использовать Deferred . Одна из самых простых структур обещаний - RSVP .
Брайан
Я в замешательстве, я не вижу ничего асинхронного в вашем коде, просто вызовы функций написаны слишком сложно.
svick

Ответы:

27

Приятно, что в обратных вызовах нет глобального состояния, и передача параметров в них тривиальна. Если у вас есть функция, download(URL, callback: (FileData)->void)то вы можете знать, что это автономная функция высшего порядка, которая, по сути, позволяет вам создать функцию «возьми и сделай это». Вы можете быть уверены, что ваш поток кода точно такой, как вы ожидаете, потому что никто другой даже не имеет дескриптора этого обратного вызова, и этот обратный вызов не знает ничего, кроме заданных параметров родительской функции. Это делает его модульным и простым в тестировании.

Если вы теперь хотите загрузить 5 файлов параллельно и выполнять разные действия, вам нужно только запустить пять из этих функций с соответствующими функциями обратного вызова. В языке с хорошим синтаксисом анонимных функций это может быть невероятно мощным.

События, с другой стороны, больше предназначены для уведомления 1..*пользователей об изменении состояния. Если вы download(URL)запускаете событие «загрузка завершена» в конце , которое запускает, processDownload()который знает, где найти данные, вы привязываете свои реализации вещей к большему количеству состояний. Как вы распределяете загрузки сейчас? Как вы по-разному обрабатываете различные загрузки? Есть download(URL, eventId)элегантный? Есть downloadAndDoThing(URL)элегантный? Едва.

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

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

Phoshi
источник
2

Я никогда не использовал события в NodeJS, но обычно я использую события JS на стороне клиента для сигнализации о том, что что-то произошло, например, AppointmentBookedEvent, так что разные части представления SPA могут реагировать на это (показать его на временной шкале, загрузить его). в панели и т. д.).
Но использование событий для оповещения о завершении метода может быть опасным путем. Вы не можете полагаться на то, что события поступают в том же порядке, в котором они были запущены, так что это может привести ко всем видам случайности ...
Нет ничего плохого в использовании событий, но есть определенный уровень детализации, который не следует использовать ; если вы придерживаетесь событий доменного имени, это нормально. Но уведомление о том, что методы закончились, слишком гранулировано.

Стефан Биллиет
источник
0

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

Таким образом, eventCenterможет выдаваться «init», который другие объекты могут затем обрабатывать для запуска кода запуска и т. Д.

Dan1701
источник