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. View Slide

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

    View Slide

  3. Паттерн PubSub

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  7. Event Emitter

    View Slide

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

    View Slide

  9. 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 Slide

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

    View Slide

  11. 11
    Event Manager

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  19. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  25. 25

    Event bubbling


    *Click*

    View Slide

  26. 26

    Event bubbling


    *Click*

    View Slide

  27. 27

    Event bubbling


    *Click*

    View Slide

  28. 28

    Event bubbling


    *Click*

    View Slide

  29. 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 Slide

  30. 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 Slide

  31. 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 Slide

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

    View Slide

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

    View Slide

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

    *Click*


    View Slide

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

    *Click*


    View Slide

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

    *Click*


    View Slide

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

    View Slide

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



    *Click*

    View Slide

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



    *Click*

    View Slide

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



    *Click*

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  44. 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 Slide

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

    View Slide

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

    View Slide

  47. 47

    View Slide

  48. 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 Slide

  49. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  54. 54
    $.throttle
    no_trailing=false

    no_trailing=true

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

    View Slide

  55. 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 Slide

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

    View Slide

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

    View Slide

  58. 58
    $.debounce
    at_begin=false

    at_begin=true

    Пауза
    Пауза

    View Slide

  59. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

  63. 63
    DataObject.someData
    Y U NO

    View Slide

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

    View Slide

  65. 65
    Module A Module B

    View Slide

  66. 66
    Module A Module B
    Data C

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  70. 70
    Module A Module B
    Data C Data C

    View Slide

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

    View Slide

  72. Events everywhere!

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide