Михаил Давыдов — JavaScript: События

77

description

 

Transcript of Михаил Давыдов — JavaScript: События

Page 1: Михаил Давыдов — JavaScript: События
Page 2: Михаил Давыдов — JavaScript: События

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

JavaScript События

Page 3: Михаил Давыдов — JavaScript: События

Паттерн PubSub

Page 4: Михаил Давыдов — JavaScript: События

4

PubSub

• Издатель (Publisher) –  Генерирует данные одного типа –  Издает только одну газету –  Издателей может быть много

• Подписчики (Subscribers) –  Подписываются на данные издателя –  Могут отписаться в любой момент

• Данные – поток –  Поздно подписался – упустил данные –  Объем и частота публикаций задается издателем

Page 5: Михаил Давыдов — JavaScript: События

5

var PubSub = function () { this.readers = []; }; PubSub.prototype = { pub: function (data) {}, sub: function (callback) {}, unsub: function (callback) {} }; // function callback(data) {}

PubSub – пример

Page 6: Михаил Давыдов — JavaScript: События

6

PubSub – особенности

• Самая простая реализация • Только 1 тип данных

–  А хочется еще и "Мурзилку" получать

• Нужно напрямую общаться с объектом

Page 7: Михаил Давыдов — JavaScript: События

Event Emitter

Page 8: Михаил Давыдов — JavaScript: События

8

Event Emitter

• Имеет много названий • Издатель

–  Генерирует данные разных типов –  Издает газеты и журналы –  Издателей может быть много

• Подписчики –  Подписываются на данные любого типа в любом количестве –  Могут отписаться в любой момент

• Данные – поток –  Поздно подписался – упустил данные –  Объем и частота публикаций задается издателем

Page 9: Михаил Давыдов — JavaScript: События

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

Page 10: Михаил Давыдов — JavaScript: События

10

Event Emitter – особенности

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

Page 11: Михаил Давыдов — JavaScript: События

11

Event Manager

Page 12: Михаил Давыдов — JavaScript: События

12

Event Manager

• Имеет много названий • Своеобразная шина данных • Единственный издатель

–  Генерирует данные разных типов

• Подписчики –  Подписываются на данные любого типа в любом количестве –  Могут отписаться в любой момент

• Данные – поток –  Поздно подписался – упустил данные –  Объем и частота публикаций задается издателем

Page 13: Михаил Давыдов — JavaScript: События

13

Похож на Event Emitter, но это Синглентон

var EventManager = { events: {}, emit: function (event, data) {}, on: function (event, callback) {}, off: function (event, callback) {} }; // function callback(data) {}

Event Manager – пример

Page 14: Михаил Давыдов — JavaScript: События

14

Event Manager – особенности

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

Page 15: Михаил Давыдов — JavaScript: События

Дополнительные фичи

Управление событиями, namespace

Накопление данных

События на дереве DOM

Делегирование событий

Фильтрация событий

Page 16: Михаил Давыдов — JavaScript: События

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

Page 17: Михаил Давыдов — JavaScript: События

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

Page 18: Михаил Давыдов — JavaScript: События

18

Управление событиями

• Группировка событий –  namespace

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

Page 19: Михаил Давыдов — JavaScript: События

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('**'); // все делегированные

Управление событиями – пример

Page 20: Михаил Давыдов — JavaScript: События

20

Накопление данных

• Опоздал с подпиской – ничего не получил –  Это не удобно

• Пользователь желает получить все –  Всю подписку журналов с нуля

• Как только подписался – сразу получил • Похоже на Promise

Page 21: Михаил Давыдов — JavaScript: События

21

jQuery DOMReady

$(function () { $(function () { console.log('Tada!'); }); });

Накопление данных – пример

Page 22: Михаил Давыдов — JavaScript: События

22

jQuery Ajax#done

var data = $.get('/'); data.done(function () { data.done(function () { console.log('Tada!'); }); });

Накопление данных – пример

Page 23: Михаил Давыдов — JavaScript: События

DOM события

События на DOM дереве

Event bubbling

Event capturing

Не всплывающие события

Page 24: Михаил Давыдов — JavaScript: События

24

Event bubbling

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

–  window или document

Page 25: Михаил Давыдов — JavaScript: События

25

<div>

Event bubbling

<div> <div>

*Click*

Page 26: Михаил Давыдов — JavaScript: События

26

<div>

Event bubbling

<div> <div>

*Click*

Page 27: Михаил Давыдов — JavaScript: События

27

<div>

Event bubbling

<div> <div>

*Click*

Page 28: Михаил Давыдов — JavaScript: События

28

<div>

Event bubbling

<div> <div>

*Click*

Page 29: Михаил Давыдов — JavaScript: События

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/

Page 30: Михаил Давыдов — JavaScript: События

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

Page 31: Михаил Давыдов — JavaScript: События

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

Page 32: Михаил Давыдов — JavaScript: События

32

Особенности

• Фазы Capturing & Bubbling идут одновременно –  Чередуются capturing, bubbling

• Каждый обработчик получает новый инстанс объекта Event

http://jsfiddle.net/h2nJU/2/

Page 33: Михаил Давыдов — JavaScript: События

Делегирование

Один обработчик – несколько целей

Основа – всплытие событий

Page 34: Михаил Давыдов — JavaScript: События

34

<ul> onclick=delegateClick

Делегирование

<li class="good"> *Click* <li class="good">

<li class="bad">

Page 35: Михаил Давыдов — JavaScript: События

35

<ul> onclick=delegateClick

Делегирование – начало события

<li class="good"> *Click* <li class="good">

<li class="bad">

Page 36: Михаил Давыдов — JavaScript: События

36

<ul> onclick=delegateClick

Делегирование – всплытие события

<li class="good"> *Click* <li class="good">

<li class="bad">

Page 37: Михаил Давыдов — JavaScript: События

37

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

Page 38: Михаил Давыдов — JavaScript: События

38

<ul> onclick=delegateClick

Делегирование

<li class="good">

<li class="good">

<li class="bad"> *Click*

Page 39: Михаил Давыдов — JavaScript: События

39

<ul> onclick=delegateClick

Делегирование – начало события

<li class="good">

<li class="good">

<li class="bad"> *Click*

Page 40: Михаил Давыдов — JavaScript: События

40

<ul> onclick=delegateClick

Делегирование – всплытие события

<li class="good">

<li class="good">

<li class="bad"> *Click*

Page 41: Михаил Давыдов — JavaScript: События

41

Событие не произойдет

contains('good') === false;

Page 42: Михаил Давыдов — JavaScript: События

42

Профит делегирования

• Меньше обработчиков событий –  Экономия памяти –  Меньше утечек памяти

• Проще работать с динамическими элементами

Page 43: Михаил Давыдов — JavaScript: События

43

Особенности делегирования

• Если событие не всплывает – ничего не получится

• Нужно максимально ограничивать событие –  Необходимо выбрать наиболее близкого делегата

• Возможны частые ложные вызовы события –  Большие затраты на вызов функции

• Ограничить делегирование у частых событий –  mousemove

• Не использовать делегирование если элемент 1

Page 44: Михаил Давыдов — JavaScript: События

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/

Page 45: Михаил Давыдов — JavaScript: События

Управление DOM событием

Прерывание всплытия

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

Page 46: Михаил Давыдов — JavaScript: События

46

Прерывание всплытия

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

• event.stopImmediatePropagation() –  Прерывает всплытие события по дереву –  Отменяет прочие обработчики

http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Event-stopPropagation

Page 47: Михаил Давыдов — JavaScript: События

47

Page 48: Михаил Давыдов — JavaScript: События

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

Page 49: Михаил Давыдов — JavaScript: События

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/

Page 50: Михаил Давыдов — JavaScript: События

debounce, throttle

Фильтрация событий

http://benalman.com/projects/jquery-throttle-debounce-plugin/

Page 51: Михаил Давыдов — JavaScript: События

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

Page 52: Михаил Давыдов — JavaScript: События

52

throttle

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

Page 53: Михаил Давыдов — JavaScript: События

53

$.throttle(timeout, callback, no_trailing);

Page 54: Михаил Давыдов — JavaScript: События

54

$.throttle

no_trailing=false

no_trailing=true

Пауза

Пауза Поток событий

Допущенные события

Page 55: Михаил Давыдов — JavaScript: События

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/

Page 56: Михаил Давыдов — JavaScript: События

56

debounce

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

N милисекунд

Page 57: Михаил Давыдов — JavaScript: События

57

$.debounce(timeout, callback, at_begin);

Page 58: Михаил Давыдов — JavaScript: События

58

$.debounce

at_begin=false

at_begin=true

Пауза

Пауза

Page 59: Михаил Давыдов — JavaScript: События

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/

Page 60: Михаил Давыдов — JavaScript: События

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

Проблемы событий

Page 61: Михаил Давыдов — JavaScript: События

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

Page 62: Михаил Давыдов — JavaScript: События

62

Вариант не удачного использования событий

DataObject.on('someData', function (data) { console.log(data); }); DataObject.trigger('giveMe:someData');

Событие геттер

Page 63: Михаил Давыдов — JavaScript: События

63 DataObject.someData

Y U NO

Page 64: Михаил Давыдов — JavaScript: События

64

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

Page 65: Михаил Давыдов — JavaScript: События

65

Module A Module B

Page 66: Михаил Давыдов — JavaScript: События

66

Module A Module B

Data C

Page 67: Михаил Давыдов — JavaScript: События

67

Module A Module B

Data C

Give me C

Page 68: Михаил Давыдов — JavaScript: События

68

Module A Module B

Data C

Data C'

Give me C

Page 69: Михаил Давыдов — JavaScript: События

69

Module A Module B

Data C

Data C'

Give me C

Page 70: Михаил Давыдов — JavaScript: События

70

Module A Module B

Data C Data C

Page 71: Михаил Давыдов — JavaScript: События

71

Накладные расходы

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

Page 72: Михаил Давыдов — JavaScript: События

Events everywhere!

Page 73: Михаил Давыдов — JavaScript: События

73

Не блокирующий I/O

• Дефрагментация времени блокировок –  Более плотная загрузка процесса

• Выгодно применять, когда время I/O больше времени обработки данных

• Меньше проблем с разделяемой памятью

Page 74: Михаил Давыдов — JavaScript: События

74

Слабое связывание

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

–  Меньше проблем синхронизации

Page 75: Михаил Давыдов — JavaScript: События

75

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

Page 76: Михаил Давыдов — JavaScript: События

76

Заключение

• События –  PubSub –  Event Emitter –  Event Manager

• Фичи событий –  namespace –  накопление данных

• DOM события –  Event Bubbling –  Делегирование –  Прерывание события –  Отмена действия по умолчанию

• Фильтрация

Page 77: Михаил Давыдов — JavaScript: События

77

Михаил Давыдов

Разработчик JavaScript

[email protected] azproduction

Спасибо