@Niki21212

Как сделать, чтобы событие вызывалось один раз?

Задание:
Cоздайте класс EventEmitter для управления событиями. У этого класса должны быть следующие методы:
.on(event, callback) - добавить обработчик события

.off(event, callback) - удалить обработчик события

.once(event, callback) - добавить обработчик события, который сработает единожды

.emit(event, [...arg]) - вызвать все обработчики события event, можно передать аргументы

Расширьте EventEmitter классом BroadcastEventEmitter так, чтобы была возможность вызвать все обработчики всех событий:
emit("*", [...arg]) - вызвать все обработчики событий, можно передать аргументы


Мой код:
class EventEmitter {
    constructor() {
          this.events = {};
    }

    on(eventName, callback) {
        !this.events[eventName] && (this.events[eventName] = []);
         this.events[eventName].push(callback);
    }

    off(eventName, callback) {
        this.events[eventName] = this.events[eventName].filter(eventCallback => callback !== eventCallback);
}

    

    once(eventName, callback) {
         const remove = this.on(events, (...args) => {
      remove();
      callback.apply(this, args);
    });
    }

    emit(eventName, args) {
       const event = this.events[eventName];
    event && event.forEach(callback => callback.call(null, args));
    }
}

class BroadcastEventEmitter extends EventEmitter {
    emit(event, ...args) {
        if (event === '*') {
            Object.keys(this.events).forEach((e) => super.emit(e, ...args));
        } else {
            super.emit(event, ...args);
        }}}


Не проходит 2 теста:
FAIL test.js
тестирование класса EventEmitter
✓ добавление слушателя события (5ms)
✓ удаление слушателя события (1ms)
✕ добавление `единоразового` слушателя (1ms)
✓ передача аргументов (4ms)
тестирование класса BroadcastEventEmitter
✓ проверка наследования от EventEmitter (1ms)
✓ вызов всех событий (1ms)
✕ передача аргументов (3ms)


Вопрос, как сделать правильно обработчик события, который сработает единожды? И передачу аргументов в BroadcastEventEmitter?
  • Вопрос задан
  • 734 просмотра
Пригласить эксперта
Ответы на вопрос 2
Alexandroppolus
@Alexandroppolus
кодир
this.events[eventName].push(callback);

вместо callback добавляй объект
this.events[eventName].push({callback, isOnce: true}); // или isOnce: false


в emit после вызова всех колбэков с помощью filter выкинь все isOnce: true
Ответ написан
Комментировать
bingo347
@bingo347 Куратор тега JavaScript
Crazy on performance...
Проблема вот тут:
const remove = this.on(events

Метод on у Вас ничего не возвращает, соответственно в remove будет undefined, функции там взяться неоткуда.
Переменной events нет в скоупе данного метода, очевидно имелась в виду eventName

А вообще, вместо массива колбэков для события лучше использовать Set, так метод off будет работать за O(1), а не за O(n) как сейчас.

В методе once можно подписываться на событие через метод on, и отписываться через метод off при его наступлении (так например делает EventEmitter из node.js). Но стоит учесть момент, что off должен работать и для once событий, а у Вас будет записан колбэк созданный в once, а не тот, что передал пользователь. Вообще проще хранить 2 коллекции: для многоразовых для одноразовых событий, ну или параметризовать колбэки (тогда лучше хранить их в Map, где ключи - колбэки, а значения - их параметры).

Ну и еще обратите внимание, что у Вас в методах emit и once колбэк пользователя вызывается по разному:
callback.apply(this, args) и callback.call(null, args)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы