Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ШРИ - JavaScript Event Model

Mikhail Davydov
September 23, 2013

ШРИ - JavaScript Event Model

Событийная модель. Базовые паттерны: PubSub, EventEmitter и EventManager. Дополнительные возможности для упрощения работы с событиями: namespace, событие с накоплением. Управление потоком событий и их фильтрация: trottle, debounce. События на DOM и Делегирование событий. Применение событийной модели для событийного ввода-вывода и организации скелета event-driven приложения.

Video https://events.yandex.ru/lib/talks/567/

Mikhail Davydov

September 23, 2013
Tweet

More Decks by Mikhail Davydov

Other Decks in Education

Transcript

  1. Михаил Давыдов
    Разработчик JavaScript
    JavaScript
    События

    View full-size slide

  2. Паттерн PubSub

    View full-size slide

  3. 4
    PubSub
    •  Издатель (Publisher)
    –  Генерирует данные одного типа
    –  Издает только одну газету
    –  Издателей может быть много
    •  Подписчики (Subscribers)
    –  Подписываются на данные издателя
    –  Могут отписаться в любой момент
    •  Данные – поток
    –  Поздно подписался – упустил данные
    –  Объем и частота публикаций задается издателем

    View full-size slide

  4. 5
    var PubSub = function () {
    this.readers = [];
    };
    PubSub.prototype = {
    pub: function (data) {},
    sub: function (callback) {},
    unsub: function (callback) {}
    };
    // function callback(data) {}
    PubSub – пример

    View full-size slide

  5. 6
    PubSub – особенности
    •  Самая простая реализация
    •  Только 1 тип данных
    –  А хочется еще и "Мурзилку" получать
    •  Нужно напрямую общаться с объектом

    View full-size slide

  6. Event Emitter

    View full-size slide

  7. 8
    Event Emitter
    •  Имеет много названий
    •  Издатель
    –  Генерирует данные разных типов
    –  Издает газеты и журналы
    –  Издателей может быть много
    •  Подписчики
    –  Подписываются на данные любого типа в любом количестве
    –  Могут отписаться в любой момент
    •  Данные – поток
    –  Поздно подписался – упустил данные
    –  Объем и частота публикаций задается издателем

    View full-size slide

  8. 9
    var EventEmitter = function () {
    // events = {"event_name": []};
    this.events = {};
    };
    EventEmitter.prototype = {
    emit: function (event, data) {},
    on: function (event, callback) {},
    off: function (event, callback) {}
    };
    // function callback(data) {}
    Event Emitter – пример

    View full-size slide

  9. 10
    Event Emitter – особенности
    •  Много разных типов данных
    •  Нужно иметь ссылку на EventEmitter

    View full-size slide

  10. 11
    Event Manager

    View full-size slide

  11. 12
    Event Manager
    •  Имеет много названий
    •  Своеобразная шина данных
    •  Единственный издатель
    –  Генерирует данные разных типов
    •  Подписчики
    –  Подписываются на данные любого типа в любом количестве
    –  Могут отписаться в любой момент
    •  Данные – поток
    –  Поздно подписался – упустил данные
    –  Объем и частота публикаций задается издателем

    View full-size slide

  12. 13
    Похож на Event Emitter, но это Синглентон
    var EventManager = {
    events: {},
    emit: function (event, data) {},
    on: function (event, callback) {},
    off: function (event, callback) {}
    };
    // function callback(data) {}
    Event Manager – пример

    View full-size slide

  13. 14
    Event Manager – особенности
    •  Много разных типов данных
    •  Об этом объекте знают все

    View full-size slide

  14. Дополнительные фичи
    Управление событиями, namespace
    Накопление данных
    События на дереве DOM
    Делегирование событий
    Фильтрация событий

    View full-size slide

  15. Их наличие зависит от
    конкретны задач

    View full-size slide

  16. Фичи направлены на
    управление группами
    событий и агрегацией

    View full-size slide

  17. 18
    Управление событиями
    •  Группировка событий
    –  namespace
    •  Легкое удаление событий
    –  Удаление события без callback
    –  Удаление по дескриптору

    View full-size slide

  18. 19
    jQuery 1.8
    var handler = function () {};
    $('body').on('click.ns', handler);
    $('body').off('click', handler); // не удобно
    $('body').off('click'); // все click
    $('body').off('.ns'); // весь namespace
    $('body').off(); // все события
    $('body').off('**'); // все делегированные
    Управление событиями – пример

    View full-size slide

  19. 20
    Накопление данных
    •  Опоздал с подпиской – ничего не получил
    –  Это не удобно
    •  Пользователь желает получить все
    –  Всю подписку журналов с нуля
    •  Как только подписался – сразу получил
    •  Похоже на Promise

    View full-size slide

  20. 21
    jQuery DOMReady
    $(function () {
    $(function () {
    console.log('Tada!');
    });
    });
    Накопление данных – пример

    View full-size slide

  21. 22
    jQuery Ajax#done
    var data = $.get('/');
    data.done(function () {
    data.done(function () {
    console.log('Tada!');
    });
    });
    Накопление данных – пример

    View full-size slide

  22. DOM события
    События на DOM дереве
    Event bubbling
    Event capturing
    Не всплывающие события

    View full-size slide

  23. 24
    Event bubbling
    •  Событие начинается с текущего элемента
    •  Поднимается по DOM дереву
    •  Последний элемент – корень дерева
    –  window или document

    View full-size slide

  24. 25

    Event bubbling


    *Click*

    View full-size slide

  25. 26

    Event bubbling


    *Click*

    View full-size slide

  26. 27

    Event bubbling


    *Click*

    View full-size slide

  27. 28

    Event bubbling


    *Click*

    View full-size slide

  28. 29
    Event bubbling – фаза по умолчанию в jQuery
    // jQuery 1.7 .on()
    $('.b-form-button').on('click', function (event) {
    console.log(this); // .b-form-button element
    });
    // Хэлперы
    $('.b-form-button').click(function (event) {
    console.log(event);
    });
    Event bubbling в jQuery
    http://api.jquery.com/on/

    http://api.jquery.com/category/events/

    http://api.jquery.com/category/events/event-object/

    View full-size slide

  29. 30
    Функция bindTo()
    BEM.DOM.decl('b-form-input', {
    onSetMod : {
    'js' : {
    'inited' : function () {
    this
    .bindTo(this.elem('input'), {
    'focus' : this.onFocus,
    'blur' : this.onBlur
    });
    }
    }
    }
    });
    Event bubbling в i-bem
    http://bem.github.com/bem-bl/sets/common-
    desktop/i-bem/i-bem.ru.html

    View full-size slide

  30. 31
    Не всплывающие события
    •  var itBubbles = event.bubbles;!
    •  Специфичные события для 1 элемента
    –  submit, focus, blur, load, unload, change, reset, scroll
    •  Некоторые события мутаций DOM
    –  DOMFocusIn, DOMFocusOut, DOMNodeRemoved
    https://developer.mozilla.org/en-US/docs/
    Mozilla_event_reference

    View full-size slide

  31. 32
    Особенности
    •  Фазы Capturing & Bubbling идут
    одновременно
    –  Чередуются capturing, bubbling
    •  Каждый обработчик получает новый инстанс
    объекта Event
    http://jsfiddle.net/h2nJU/2/

    View full-size slide

  32. Делегирование
    Один обработчик – несколько целей
    Основа – всплытие событий

    View full-size slide

  33. 34
    onclick=delegateClick
    Делегирование

    *Click*


    View full-size slide

  34. 35
    onclick=delegateClick
    Делегирование – начало события

    *Click*


    View full-size slide

  35. 36
    onclick=delegateClick
    Делегирование – всплытие события

    *Click*


    View full-size slide

  36. 37
    var isTarget =
    event.target.classList
    .contains('good');

    View full-size slide

  37. 38
    onclick=delegateClick
    Делегирование



    *Click*

    View full-size slide

  38. 39
    onclick=delegateClick
    Делегирование – начало события



    *Click*

    View full-size slide

  39. 40
    onclick=delegateClick
    Делегирование – всплытие события



    *Click*

    View full-size slide

  40. 41
    Событие не произойдет
    contains('good') === false;

    View full-size slide

  41. 42
    Профит делегирования
    •  Меньше обработчиков событий
    –  Экономия памяти
    –  Меньше утечек памяти
    •  Проще работать с динамическими
    элементами

    View full-size slide

  42. 43
    Особенности делегирования
    •  Если событие не всплывает – ничего не
    получится
    •  Нужно максимально ограничивать событие
    –  Необходимо выбрать наиболее близкого делегата
    •  Возможны частые ложные вызовы события
    –  Большие затраты на вызов функции
    •  Ограничить делегирование у частых
    событий
    –  mousemove
    •  Не использовать делегирование если
    элемент 1

    View full-size slide

  43. 44
    // jQuery 1.7+ .on()
    $('.b-container')
    .on('click', '.b-item', function (event) {
    console.log(this); // .b-item
    });
    // jQuery 1.3+
    $('.b-item')
    .live('click', function (event) {
    console.log(this); // .b-item
    });
    // === $(document).on('click', '.b-item')
    Делегирование в jQuery
    http://api.jquery.com/on/

    http://api.jquery.com/live/

    View full-size slide

  44. Управление DOM событием
    Прерывание всплытия
    Прерывание действия по умолчанию

    View full-size slide

  45. 46
    Прерывание всплытия
    •  event.stopPropagation()
    –  Прерывает всплытие события по дереву
    •  event.stopImmediatePropagation()
    –  Прерывает всплытие события по дереву
    –  Отменяет прочие обработчики
    http://www.w3.org/TR/DOM-Level-2-Events/
    events.html#Events-Event-stopPropagation

    View full-size slide

  46. 48
    Прерывание действия по умолчанию
    •  Действие по умолчанию
    –  Переход по ссылке
    –  Раскрытие
    –  Сабмит формы
    –  Фокус в инпут
    –  Снятие фокуса
    •  event.preventDefault()
    –  Перерывает это действие
    •  Некоторые действия прервать нельзя
    –  var isCanPrevent = event.cancelable;
    –  resize, scroll, focus, error, load, unload, DOM*, …
    https://developer.mozilla.org/en-US/docs/DOM/
    event.preventDefault

    View full-size slide

  47. 49
    $('.b-link').click('click', function (event) {
    return false; // preventDefault+stopPropagation
    });
    $('.b-form').click('submit', function (event) {
    return isValid(this); // this - .b-form
    });
    $('.b-link').click('click', function (event) {
    event.preventDefault();
    event.stopPropagation();
    });
    Прерывание событий jQuery
    http://api.jquery.com/on/

    http://api.jquery.com/live/

    View full-size slide

  48. debounce, throttle
    Фильтрация событий
    http://benalman.com/projects/jquery-throttle-
    debounce-plugin/

    View full-size slide

  49. Бывает, что событий очень
    много, а обрабатывать
    каждое дорого

    View full-size slide

  50. 52
    throttle
    •  Фильтрация частоты сообщений
    •  Событие вызывается не чаще чем раз в N
    миллисекунд

    View full-size slide

  51. 53
    $.throttle(timeout,
    callback,
    no_trailing);

    View full-size slide

  52. 54
    $.throttle
    no_trailing=false

    no_trailing=true

    Пауза
    Пауза
    Поток событий
    Допущенные события

    View full-size slide

  53. 55
    var log = $.throttle(250, function () {
    console.log(arguments);
    });
    $(window).scroll(log);
    $(window).off('scroll', log);
    $.throttle
    http://benalman.com/code/projects/jquery-throttle-
    debounce/examples/throttle/

    View full-size slide

  54. 56
    debounce
    •  Склеивает вызовы в один
    •  Событие вызывается только после паузы в
    N милисекунд

    View full-size slide

  55. 57
    $.debounce(timeout,
    callback,
    at_begin);

    View full-size slide

  56. 58
    $.debounce
    at_begin=false

    at_begin=true

    Пауза
    Пауза

    View full-size slide

  57. 59
    function suggest(event) {};
    $('input').keyup(suggest);
    $('input').keyup($.debounce(250, suggest));
    $('input').unbind('keyup', suggest);
    $.debounce
    http://benalman.com/code/projects/jquery-throttle-
    debounce/examples/debounce/

    View full-size slide

  58. Неуместное использование
    Накладные расходы
    Проблемы событий

    View full-size slide

  59. События это круто –
    давайте везде
    использовать!!1!

    View full-size slide

  60. 62
    Вариант не удачного использования событий
    DataObject.on('someData', function (data) {
    console.log(data);
    });
    DataObject.trigger('giveMe:someData');
    Событие геттер

    View full-size slide

  61. 63
    DataObject.someData
    Y U NO

    View full-size slide

  62. 64
    События – поток. Их лучше
    использовать как поток
    данных

    View full-size slide

  63. 65
    Module A Module B

    View full-size slide

  64. 66
    Module A Module B
    Data C

    View full-size slide

  65. 67
    Module A Module B
    Data C
    Give me C

    View full-size slide

  66. 68
    Module A Module B
    Data C
    Data C'
    Give me C

    View full-size slide

  67. 69
    Module A Module B
    Data C
    Data C'
    Give me C

    View full-size slide

  68. 70
    Module A Module B
    Data C Data C

    View full-size slide

  69. 71
    Накладные расходы
    •  Событие – функция
    –  n объектов, k ресурсов = n*k функций
    –  функция занимает ресурсы
    –  лишние скоупы, сборка мусора и JIT-компиляция
    –  вызов кучи функций
    –  утечки памяти

    View full-size slide

  70. Events everywhere!

    View full-size slide

  71. 73
    Не блокирующий I/O
    •  Дефрагментация времени блокировок
    –  Более плотная загрузка процесса
    •  Выгодно применять, когда время I/O больше
    времени обработки данных
    •  Меньше проблем с разделяемой памятью

    View full-size slide

  72. 74
    Слабое связывание
    •  Элементы не знают о программе
    •  Элементы общаются только событиями
    •  Меньше разделенной памяти
    –  Меньше проблем синхронизации

    View full-size slide

  73. 75
    trigger(message)! on(message, callback)!

    View full-size slide

  74. 76
    Заключение
    •  События
    –  PubSub
    –  Event Emitter
    –  Event Manager
    •  Фичи событий
    –  namespace
    –  накопление данных
    •  DOM события
    –  Event Bubbling
    –  Делегирование
    –  Прерывание события
    –  Отмена действия по умолчанию
    •  Фильтрация

    View full-size slide

  75. 77
    Михаил Давыдов
    Разработчик JavaScript
    [email protected]
    azproduction
    Спасибо

    View full-size slide