Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Паттерн PubSub

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Event Emitter

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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 – пример

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

11 Event Manager

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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('**'); // все делегированные Управление событиями – пример

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

25
Event bubbling
*Click*

Slide 26

Slide 26 text

26
Event bubbling
*Click*

Slide 27

Slide 27 text

27
Event bubbling
*Click*

Slide 28

Slide 28 text

28
Event bubbling
*Click*

Slide 29

Slide 29 text

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/

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

34
    onclick=delegateClick Делегирование
  • *Click*

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

38
    onclick=delegateClick Делегирование
  • *Click*

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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/

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

47

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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/

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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/

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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/

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

63 DataObject.someData Y U NO

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

65 Module A Module B

Slide 66

Slide 66 text

66 Module A Module B Data C

Slide 67

Slide 67 text

67 Module A Module B Data C Give me C

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

70 Module A Module B Data C Data C

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

Events everywhere!

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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