Event Emitter

Баумгертнер Александр / Нетология

2016

Event Emitter

Баумгертнер Александр / Нетология

Александр Баумгертнер

Фронтендр разработчик Griddynamics

План

  1. Описание шаблона проектирования Наблюдатель [Observer]
  2. Примеры в клиентских библиотеках (addEventListener, jQuery.on)
  3. Описание модуля events в Node.js. Класс EventEmitter.
  4. Методы экземпляра класса EventEmitter
  5. Модули Node.js использующие EventEmitter
  6. Материалы
  7. Задание

Наблюдатель [Observer]

было:


    let user_1, user_2, user_3, user_4, chatApplication;
    /* ... */
    chatApplication.send = function(message) {
      // вызовы метода чтения у всех пользователей
      // должны быть в коде метода `send`
      user_1.read(message);
      user_2.read(message);
      user_3.read(message);
      user_4.read(message);
    };
  

Наблюдатель [Observer]

стало:


    chatApplication.on('send',
      (message) => { user_1.read(message); }
    );

    // где-то в другом месте кода
    chatApplication.on('send',
      (message) => { user_2.read(message); }
    );

    // где-то в конце кода
    chatApplication.on('send',
      (message) => { user_4.read(message); }
    );
  

Наблюдатель [Observer]

Примеры в клиентских библиотеках

js DOM

        
        let button = document.querySelector('.selector');
        let clickHandler = function(e) { /* код обработчика */ };

        // Подписаться на клик по кнопке
        button.addEventListener('click', clickHandler);

        // Отписаться от клика
        button.removeEventListener('click', clickHandler);
      
      

Примеры в клиентских библиотеках

jquery.on

        
        $(document)
          .on('ajaxSend', function() {
            // показать лоадер
            $('#loading').show();
          })
          .on('ajaxComplete', function() {
            // скрыть лоадер
            $('#loading').hide();
        });
      
      

Node.js: Теория

Класс EventEmitter

API Doc: events

Пример использования:


    // В версиях до 4.0.0:
    // require('events').EventEmitter
    const EventEmitter = require('events');

    // Создать объект-экземпляр (instance)
    const myEmitter = new EventEmitter();

    // Добавить обработчик _до_ вызова события
    myEmitter.on('myEvent', (message) => { console.log(message) });

    // Вызов (trigger) события
    myEmitter.emit('myEvent', 'Привет, Мир!');
  

Методы экземпляра класса EventEmitter

emitter.on

Добавляет обработчик события, вызываемый каждый раз при событии.

Параметры (api):


      const EventEmitter = require('events');
      const myEmitter = new EventEmitter();

      myEmitter.on('myEvent', (data) => {
        console.log(`Произошло событие myEvent, данные: ${data}`);
      });
    

emitter.once

Тоже, что и emitter.on, но обработчик события будет вызван один раз.


     myEmitter.once('myEvent', (data) => {
        console.log(`Произошло событие myEvent, ${data}`);
      });

     myEmitter.emit('myEvent', 'Привет, Мир!');
     // console.log: Произошло событие myEvent, Привет, Мир!

     myEmitter.emit('myEvent', 'Еще раз, Привет, Мир!');
     // ничего не произойдет

  

emitter.prependListener

Тоже, что и emitter.on, но добавляет обработчик перед остальными.


    myEmitter.on('myEvent', (data) => {
      console.log(`Произошло событие myEvent, сообщение: ${data.message}`);
    });

    myEmitter.prependListener('myEvent', () => {
      console.log(`Последним добавлен — первым вызван`);
    });
  

emitter.prependOnceListener — обработчик вызывается один раз

emitter.emit

emitter.emit(eventName[, arg1][, arg2][, ...])

Вызывает событие eventName,
можно передать данные arg1, arg2, ...

Параметры (api):

emitter.emit, пример


    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();


    /**
     * {String} 'myEvent' — Имя события
     * {*} 'Привет, Мир!' — Данные события
     */
     myEmitter.emit('myEvent', 'Привет, Мир!');
  

emitter.emit('error')

Если не перехватить событие error, то оно выбросит исключение, которое остановит программу


    emitter.emit('error');
    // events.js:1
    //  throw err;
    //  ^
    //
    // log: Error: Uncaught, unspecified "error" event.
    // Программа завершилась.
  

emitter.eventNames

Возвращает массив событий, для которых были добавлены обработчики.


    myEmitter.on('myEvent_1', () => {});
    myEmitter.on('myEvent_2', () => {});

    console.log('eventNames: ', myEmitter.eventNames());
    // log:  eventNames:  [ 'myEvent_1', 'myEvent_2' ]
  

emitter.removeListener

emitter.removeListener(eventName, listener)

Удаляет обработчик listener события eventName

Параметры

emitter.removeListener, пример


    // Обработчик нужно сохранить в переменную
    let myListener = (message) => { console.log(message); };

    // Добавить обработчик события `myEvent`
    myEmitter.on('myEvent', myListener);

    // Удалить обработчик события `myEvent`
    myEmitter.removeListener('myEvent', myListener);
  

emitter.removeAllListeners

Удаляет все обработчики событий


    myEmitter.on('myEvent_1', () => {});
    myEmitter.on('myEvent_2', () => {});
    myEmitter.on('myEvent_3', () => {});

    myEmitter.removeAllListeners();
  

emitter.getMaxListeners

emitter.getMaxListeners()

Возвращает максимальное количество обработчиков, которое можно добавить к emitter.

По умолчанию — 10.

При привышении количества — предупреждение в консоли.
Warning: Possible EventEmitter memory leak detected. Use emitter.setMaxListeners() to increase limit.

Цель — экономия памяти и быстродействие.

emitter.setMaxListeners

emitter.setMaxListeners(n)

Устанавливает значение максимального количества обработчиков, которое можно добавить к emitter

Параметры

emitter.setMaxListeners, пример


    myEmitter.setMaxListeners(3);

    myEmitter.on('myEvent_1', () => {});
    myEmitter.on('myEvent_1', () => {});
    myEmitter.on('myEvent_1', () => {});
    myEmitter.on('myEvent_1', () => {});
    // Warning: Possible EventEmitter memory leak detected.
    // 4 myEvent_1 listeners added.
    // Use emitter.setMaxListeners()
    // to increase limit


  

Пример программы

chat.js

Модули Node.js, использующие EventEmitter

Материалы

Домашнее Задание — часть 1

Доработать chat.js

Полная ссылка: https://github.com/easy-deep-learning/event-emitter/blob/master/examples/app/chat.js

1.1 Добавить обработчик события message для Чата Вебинара (webinarChat), который выводит в консоль сообщение 'Готовлюсь к ответу'. Обработчик создать в отдельной функции.

1.2 Для вконтакте (vkChat) установить максимальное количество обработчиков событий, равное 2.

1.3 Добавить обработчик 'Готовлюсь к ответу' из пп. 1.1 к чату вконтакте.

Домашнее Задание — часть 2

Доработать chat.js

2.1 В классе чата ChatApp добавить метод close, который будет вызывать событие close (событие вызывается один раз, setInterval как в констукторе, не нужен).

2.2 Для чата вконтакте (vkChat) добавить обработчик close, выводящий в консоль текст "Чат вконтакте закрылся :(".

2.3 Вызывать у чата вконтакте метод close().

Домашнее Задание — на зачет с отличием

Доработать chat.js

Добавить код, который через 30 секунд отписывает chatOnMessage от вебинара webinarChat :).

Разбить существующий код на модули, запускаемый файл должен быть index.js или index.js

Как предоставить код домашней работы на проверку

Способы предоставить домашнее задание в порядке приоритета:

  1. Исходный код на BitBucket или GitHub
  2. Код в песочнице CodePen или JSFiddle

Не смогу проверить и помочь если прислать:

Fork me on GitHub