Search
Write a publication
Pull to refresh

Comments 19

может быть несколько одинаковых функций для одного события;

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

И второй вопрос, что будет, если обработчик событий сам позовёт emit?

по второму вопросу не понял, раскрой пожалуйста подробнее

Вы "подписали" функци на событие. Произошло событие. Её позвали. Она сама сгенерировала еще одно событие. Её опять позвали. И так по кругу, пока стек не кончится.

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

Как разработчик, ловивший такие ситуации, крайне рекомендую иметь для такого кейса хотя бы двойную буфферизацию - то что "в работе" и то что будет обновляться на следующей итерации.

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

Выглядит, что немного не хватает тестов, чтобы понимать проблемы с эргономикой этого класса, да и вцелом корректности.

Вы не с той стороны заходите.

Тут есть разные варианты. Но отталкиваться надо от того, что вы хотите получить. От желаемого поведения с учётом всех нюансов, а не от деталей реализации.

А то получится в итоге, "что выросло, то выросло".

Например, если callback в процессе своей работы генерирует событие, на которое он подписан, что должно произойти? Его должны сразу же позвать, не дожидаясь завершения? Или его должны позвать еще раз, когда он закончит текущую работу? Или все события, вызванные работой callback-ов должны сложиться в очередь, которую будут разбирать после того, как отработают события, уже имеющиеся в очереди? Или что-то еще?

Если предполагается какой-то из вариантов отложенной доставки событий, каковы гарантии в плане порядка их доставки?

Итоговая модель, которая у вас получится, понятна ли она программистам, насколько сложно её описать, удобно ли ей пользоваться?

Только зная ответы на эти вопросы можно решать, как внутри себя должна быть устроена реализация.

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

А то получится в итоге, "что выросло, то выросло".


Ну так... Да.. Это же просто описание моего опыта решения конкретной задачи на конкретном собеседовании, статья ведь кажется не называется "Я написал лучший EventEmitter", или "Научу писать лучший EventEmitter"? Вроде нет.
Возможно мы по разному понимаем цель её написания - я просто поделился опытом, и не стремился научить кого-то работать по best practices, или моему пониманию прекрасного.
Вы нашли какие-то недостатки? Супер, спасибо что поделились! Я согласен, что код не идеален, оно как бы изначально и не подразумевалось как пример идеального решения :)

Опять же - вы ведь можете написать свой вариант с идеальным (на ваш взгляд решением), это будет очень круто, я с удовольствием ознакомлюсь, наверное даже научусь чему-то новому!

Вот кому может понадобиться дважды подписать одну функцию?

Вообще это просто условие задачи, которое дали на конкретном собеседовании.
Но от себя навскидку могу предположить такие кейсы:
1) если в дальнейшем планируется расширение функционала с возможностью задания дополнительных флагов объекту listener (once/priority и тд) - может возникнуть необходимость хранения таких разных listener с одной и той же функцией
2) возможность передать разные варианты контекста, вроде такого:

emitter.on("update", handler.bind(moduleA));
emitter.on("update", handler.bind(moduleB));

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

В языке, в котором есть лямбды и замыкания, вроде нет проблем приложить к вызову функции дополнительный контекст...

Мы сейчас перебираем варианты решения абстрактной задачи с какого-то конкретного собеседования, в поисках того решения, который понравится конкретно вам, правильно я понимаю? :)

Если вам так нравятся такие задачки, попробуйте написать свой bind. Куда познавательней, чем ивент емитер))))

Да, вполне можно пробнуть, надо ознакомиться, спасибо за рекомендацию!

Код изначальной задачи вызывает вопросы) во-первых для events было бы явно удобнее использовать Map, во-вторых зачем здесь класс в принципе? Со всем вышеуказанным справится стрелочная(божечки, даже без this) функция, которая вернёт объект с указанными методами, а результат её вызова будет так же записан в константу, с которой дальше проходят все операции

Думаю, что вопросы релевантны, согласен с ними, но задача была поставлена таким образом и на тот момент я просто "работал с чем дали" :)

Как может быть отписка в процессе emita? У вас же все синхронно.

const emitter = new EventEmitter();

function listener1() {
  console.log("listener1: сработал и отписался");
  emitter.off("event", listener1); // отписка прямо во время emit
}

function listener2() {
  console.log("listener2: сработал");
}

emitter.on("event", listener1);
emitter.on("event", listener2);

Если имеется дубликат подписки на одну и ту же функцию, какая разница, какую версию убирать? Даже если функция работает со состоянием, я не вижу разницы. Можно ли привести конкретный пример, когда удаление "неправильного" дубликата может привести к проблемам? В условии ведь нет упомнинания детерминированности последовательности выполнения функций в emit, верно?

Sign up to leave a comment.

Articles