ШРИ - JavaScript Event Model

B827d6cfdfbcfce33700b0e6cc03e344?s=47 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/

B827d6cfdfbcfce33700b0e6cc03e344?s=128

Mikhail Davydov

September 23, 2013
Tweet

Transcript

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

  3. Паттерн PubSub

  4. 4 PubSub •  Издатель (Publisher) –  Генерирует данные одного типа

    –  Издает только одну газету –  Издателей может быть много •  Подписчики (Subscribers) –  Подписываются на данные издателя –  Могут отписаться в любой момент •  Данные – поток –  Поздно подписался – упустил данные –  Объем и частота публикаций задается издателем
  5. 5 var PubSub = function () { this.readers = [];

    }; PubSub.prototype = { pub: function (data) {}, sub: function (callback) {}, unsub: function (callback) {} }; // function callback(data) {} PubSub – пример
  6. 6 PubSub – особенности •  Самая простая реализация •  Только

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

  8. 8 Event Emitter •  Имеет много названий •  Издатель – 

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

    •  Нужно иметь ссылку на EventEmitter
  11. 11 Event Manager

  12. 12 Event Manager •  Имеет много названий •  Своеобразная шина

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

    = { events: {}, emit: function (event, data) {}, on: function (event, callback) {}, off: function (event, callback) {} }; // function callback(data) {} Event Manager – пример
  14. 14 Event Manager – особенности •  Много разных типов данных

    •  Об этом объекте знают все
  15. Дополнительные фичи Управление событиями, namespace Накопление данных События на дереве

    DOM Делегирование событий Фильтрация событий
  16. Их наличие зависит от конкретны задач

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

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

    удаление событий –  Удаление события без callback –  Удаление по дескриптору
  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('**'); // все делегированные Управление событиями – пример
  20. 20 Накопление данных •  Опоздал с подпиской – ничего не

    получил –  Это не удобно •  Пользователь желает получить все –  Всю подписку журналов с нуля •  Как только подписался – сразу получил •  Похоже на Promise
  21. 21 jQuery DOMReady $(function () { $(function () { console.log('Tada!');

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

    data.done(function () { console.log('Tada!'); }); }); Накопление данных – пример
  23. DOM события События на DOM дереве Event bubbling Event capturing

    Не всплывающие события
  24. 24 Event bubbling •  Событие начинается с текущего элемента • 

    Поднимается по DOM дереву •  Последний элемент – корень дерева –  window или document
  25. 25 <div> Event bubbling <div> <div> *Click*

  26. 26 <div> Event bubbling <div> <div> *Click*

  27. 27 <div> Event bubbling <div> <div> *Click*

  28. 28 <div> Event bubbling <div> <div> *Click*

  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/
  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
  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
  32. 32 Особенности •  Фазы Capturing & Bubbling идут одновременно – 

    Чередуются capturing, bubbling •  Каждый обработчик получает новый инстанс объекта Event http://jsfiddle.net/h2nJU/2/
  33. Делегирование Один обработчик – несколько целей Основа – всплытие событий

  34. 34 <ul> onclick=delegateClick Делегирование <li class="good"> *Click* <li class="good"> <li

    class="bad">
  35. 35 <ul> onclick=delegateClick Делегирование – начало события <li class="good"> *Click*

    <li class="good"> <li class="bad">
  36. 36 <ul> onclick=delegateClick Делегирование – всплытие события <li class="good"> *Click*

    <li class="good"> <li class="bad">
  37. 37 var isTarget = event.target.classList .contains('good');

  38. 38 <ul> onclick=delegateClick Делегирование <li class="good"> <li class="good"> <li class="bad">

    *Click*
  39. 39 <ul> onclick=delegateClick Делегирование – начало события <li class="good"> <li

    class="good"> <li class="bad"> *Click*
  40. 40 <ul> onclick=delegateClick Делегирование – всплытие события <li class="good"> <li

    class="good"> <li class="bad"> *Click*
  41. 41 Событие не произойдет contains('good') === false;

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

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

    не получится •  Нужно максимально ограничивать событие –  Необходимо выбрать наиболее близкого делегата •  Возможны частые ложные вызовы события –  Большие затраты на вызов функции •  Ограничить делегирование у частых событий –  mousemove •  Не использовать делегирование если элемент 1
  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/
  45. Управление DOM событием Прерывание всплытия Прерывание действия по умолчанию

  46. 46 Прерывание всплытия •  event.stopPropagation() –  Прерывает всплытие события по

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

  48. 48 Прерывание действия по умолчанию •  Действие по умолчанию – 

    Переход по ссылке –  Раскрытие <select> –  Сабмит формы –  Фокус в инпут –  Снятие фокуса •  event.preventDefault() –  Перерывает это действие •  Некоторые действия прервать нельзя –  var isCanPrevent = event.cancelable; –  resize, scroll, focus, error, load, unload, DOM*, … https://developer.mozilla.org/en-US/docs/DOM/ event.preventDefault
  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/
  50. debounce, throttle Фильтрация событий http://benalman.com/projects/jquery-throttle- debounce-plugin/

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

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

    чаще чем раз в N миллисекунд
  53. 53 $.throttle(timeout, callback, no_trailing);

  54. 54 $.throttle no_trailing=false no_trailing=true Пауза Пауза Поток событий Допущенные события

  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/
  56. 56 debounce •  Склеивает вызовы в один •  Событие вызывается

    только после паузы в N милисекунд
  57. 57 $.debounce(timeout, callback, at_begin);

  58. 58 $.debounce at_begin=false at_begin=true Пауза Пауза

  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/
  60. Неуместное использование Накладные расходы Проблемы событий

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

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

    console.log(data); }); DataObject.trigger('giveMe:someData'); Событие геттер
  63. 63 DataObject.someData Y U NO

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

  65. 65 Module A Module B

  66. 66 Module A Module B Data C

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

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

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

    me C
  70. 70 Module A Module B Data C Data C

  71. 71 Накладные расходы •  Событие – функция –  n объектов,

    k ресурсов = n*k функций –  функция занимает ресурсы –  лишние скоупы, сборка мусора и JIT-компиляция –  вызов кучи функций –  утечки памяти
  72. Events everywhere!

  73. 73 Не блокирующий I/O •  Дефрагментация времени блокировок –  Более

    плотная загрузка процесса •  Выгодно применять, когда время I/O больше времени обработки данных •  Меньше проблем с разделяемой памятью
  74. 74 Слабое связывание •  Элементы не знают о программе • 

    Элементы общаются только событиями •  Меньше разделенной памяти –  Меньше проблем синхронизации
  75. 75 trigger(message)! on(message, callback)!

  76. 76 Заключение •  События –  PubSub –  Event Emitter – 

    Event Manager •  Фичи событий –  namespace –  накопление данных •  DOM события –  Event Bubbling –  Делегирование –  Прерывание события –  Отмена действия по умолчанию •  Фильтрация
  77. 77 Михаил Давыдов Разработчик JavaScript azproduction@yandex-team.ru azproduction Спасибо