Реализовать цепочечный EventEmitter с on, off и emit
Реализуйте класс EventEmitter с методами on(event, fn), off(event, fn) и emit(event, ...args). Требования: emit вызывает каждого зарегистрированного слушателя события с пробрасываемыми аргументами; on/off возвращают this для цепочки; слушатель, бросивший ошибку, не должен останавливать остальных.
class EventEmitter {
// ваш код здесь
}
Допишите реализацию.
Храните Map от имени события к Set слушателей. on добавляет слушателя и возвращает this; off удаляет его и возвращает this. emit идёт по копии множества слушателей, оборачивая каждый вызов в try/catch, чтобы один бросивший слушатель не прервал остальных. Копирование перед обходом также делает безопасным добавление и удаление слушателей во время emit.
- ✗Позволять одному бросившему слушателю прервать остальных вместо изоляции каждого вызова
- ✗Обходить живую коллекцию слушателей, ломая добавление/удаление во время emit
- ✗Забыть вернуть
thisизon/off, что ломает цепочку вызовов
- →Как добавить
once(event, fn), который сам снимается после первого emit? - →Зачем копировать множество слушателей перед обходом внутри
emit?
Решение
Map имён событий к Set слушателей, изоляция ошибок и возврат this.
class EventEmitter {
#listeners = new Map();
on(event, fn) {
if (!this.#listeners.has(event)) this.#listeners.set(event, new Set());
this.#listeners.get(event).add(fn);
return this;
}
off(event, fn) {
this.#listeners.get(event)?.delete(fn);
return this;
}
emit(event, ...args) {
const set = this.#listeners.get(event);
if (!set) return false;
for (const fn of [...set]) { // копия: безопасно при on/off во время emit
try { fn(...args); }
catch (err) { console.error(err); } // изоляция: один сбой не рушит остальных
}
return true;
}
}
Как это работает
Set на событие автоматически отсекает дубли слушателей и даёт delete за O(1). emit обходит копию множества, поэтому слушатель, который во время рассылки делает on/off, не ломает итерацию. Каждый вызов обёрнут в try/catch, так что брошенная ошибка изолируется, а остальные слушатели всё равно отрабатывают. on и off возвращают this, что позволяет писать bus.on(...).on(...).