76

JavaScript. Event Loop and Timers (in russian)

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: JavaScript. Event Loop and Timers (in russian)
Page 2: JavaScript. Event Loop and Timers (in russian)

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

Асинхронность, работа с сервером

Page 3: JavaScript. Event Loop and Timers (in russian)

3

Задача

• Качаем 1 файл • Обрабатываем • После отправляем данные на 2 сервера • Вызываем alert()

Page 4: JavaScript. Event Loop and Timers (in russian)

4

Псевдокод программы

var file = getFile('/filename.jpg'); file = jpg2png(file); sendFile(file, 'http://server1.ru/'); sendFile(file, 'http://server2.ru/'); alert('tada!');

Page 5: JavaScript. Event Loop and Timers (in russian)

5

1. Подготовка

var file = getFile('/filename.jpg'); file = jpg2png(file); sendFile(file, 'http://server1.ru/'); sendFile(file, 'http://server2.ru/'); alert('tada!');

Старт TCP/IP сессии Отправка HTTP запроса Получение данных …

Page 6: JavaScript. Event Loop and Timers (in russian)

6

2. Обработка

var file = getFile('/filename.jpg'); file = jpg2png(file); sendFile(file, 'http://server1.ru/'); sendFile(file, 'http://server2.ru/'); alert('tada!');

Переделываем JPG в PNG

Page 7: JavaScript. Event Loop and Timers (in russian)

7

3. Отправка

var file = getFile('/filename.jpg'); file = jpg2png(file); sendFile(file, 'http://server1.ru/'); sendFile(file, 'http://server2.ru/'); alert('tada!');

Старт TCP/IP сессии Отправка HTTP запроса Получение данных …

Page 8: JavaScript. Event Loop and Timers (in russian)

8

4. Алерт

var file = getFile('/filename.jpg'); file = jpg2png(file); sendFile(file, 'http://server1.ru/'); sendFile(file, 'http://server2.ru/'); alert('tada!');

Рисуем окно через системное API

Page 9: JavaScript. Event Loop and Timers (in russian)

9

Схема загрузки линейной программы

время

Блокировка Блокировка Блокировка

Загрузка Отправка Отправка

Подготовка Обработка Отправка Алерт

Page 10: JavaScript. Event Loop and Timers (in russian)

10

Большую часть времени эта программа ждет I/O

Page 11: JavaScript. Event Loop and Timers (in russian)

11

Стоимость операций I/O

• L1-кэш 3 цикла • L2-кэш 14 циклов • RAM 250 циклов • Диск 41 000 000 циклов • Сеть 240 000 000

Page 12: JavaScript. Event Loop and Timers (in russian)

12

На помощь приходят: треды, потоки, форки…

Page 13: JavaScript. Event Loop and Timers (in russian)

13

дедлоки, мьютексы, проблемы с синхронизацией и параллельное программирование

Page 14: JavaScript. Event Loop and Timers (in russian)

14

Page 15: JavaScript. Event Loop and Timers (in russian)

Событийная программа

Page 16: JavaScript. Event Loop and Timers (in russian)

16

Идея событийного программирования

• Любое действие – событие –  Начало программы –  Клик на кнопку –  Событие во времени –  Конец чтения файла…

• Программа не ждет I/O –  Загрузка процесса предельно близка к 100%

• Подписывается на события I/O • Выполняет код, когда событие наступило

Page 17: JavaScript. Event Loop and Timers (in russian)

17

Сообщи мне когда придет файл, а пока я буду делать что-то полезное

Page 18: JavaScript. Event Loop and Timers (in russian)

18

Псевдокод событийной программы

var servers = [ 'http://serv1.ru/', 'http://serv2.ru/']; getFile('filename.jpg').then(function (file){ file = jpg2png(file); sendTo(file, servers).then(function (){ alert('tada!'); }); });

Page 19: JavaScript. Event Loop and Timers (in russian)

19

1. Подготовка

var servers = [ 'http://serv1.ru/', 'http://serv2.ru/']; getFile('filename.jpg').then(function (file){ file = jpg2png(file); sendTo(file, servers).then(function (){ alert('tada!'); }); });

Когда файл скачается вызови эту функцию

Page 20: JavaScript. Event Loop and Timers (in russian)

20

2. Обработка

var servers = [ 'http://serv1.ru/', 'http://serv2.ru/']; getFile('filename.jpg').then(function (file){ file = jpg2png(file); sendTo(file, servers).then(function (){ alert('tada!'); }); });

Кодируем в PNG

Page 21: JavaScript. Event Loop and Timers (in russian)

21

3. Отправка

var servers = [ 'http://serv1.ru/', 'http://serv2.ru/']; getFile('filename.jpg').then(function (file){ file = jpg2png(file); sendTo(file, servers).then(function (){ alert('tada!'); }); });

Когда файлы отправятся вызови эту функцию

Page 22: JavaScript. Event Loop and Timers (in russian)

22

4. Алерт

var servers = [ 'http://serv1.ru/', 'http://serv2.ru/']; getFile('filename.jpg').then(function (file){ file = jpg2png(file); sendTo(file, servers).then(function (){ alert('tada!'); }); });

Рисуем системное окно

Page 23: JavaScript. Event Loop and Timers (in russian)

23

Схема загрузки событийной программы

время

Ожидание Ожидание

Запрос

Подготовка Обработка Отправка Алерт

Page 24: JavaScript. Event Loop and Timers (in russian)

24

Профит

• Блокировка → Ожидание запроса • Программа не блокируется • Отправляет файлы параллельно • 1 тред может обслуживать несколько соединений

Page 25: JavaScript. Event Loop and Timers (in russian)

25

Event Loop

Page 26: JavaScript. Event Loop and Timers (in russian)

26

Event Loop

• Один поток • Использует системные команды

–  *NIX: select, epoll, kqueue –  Win: GetMessage, PeekMessage

• Основа – список событий • Подписываемся на событие • Выполняем код, когда событие произошло • Список событий пуст – конец

Page 27: JavaScript. Event Loop and Timers (in russian)

27

Кадр или Фрейм Event Loop === обработчик события

Page 28: JavaScript. Event Loop and Timers (in russian)

28

Event Loop

var servers = [ 'http://serv1.ru/', 'http://serv2.ru/']; getFile('filename.jpg').then(function (file){ file = jpg2png(file); sendTo(file, servers).then(function (){ alert('tada!'); }); });

Список событий

Когда придет запрос к серверу – запусти этот код

Запрос к серверу

Page 29: JavaScript. Event Loop and Timers (in russian)

29

Event Loop

var servers = [ 'http://serv1.ru/', 'http://serv2.ru/']; getFile('filename.jpg').then(function (file){ file = jpg2png(file); sendTo(file, servers).then(function (){ alert('tada!'); }); });

Список событий

Пришел запрос к северу, выполняем обработчик Когда файл прочитается – запусти этот код

Файл прочитан

Page 30: JavaScript. Event Loop and Timers (in russian)

30

Event Loop

var servers = [ 'http://serv1.ru/', 'http://serv2.ru/']; getFile('filename.jpg').then(function (file){ file = jpg2png(file); sendTo(file, servers).then(function (){ alert('tada!'); }); });

Список событий

Файл прочитался, выполняем обработчик Когда файлы отправятся – запусти этот код

Файл отправлен

Файл отправлен

Page 31: JavaScript. Event Loop and Timers (in russian)

31

А что если будет несколько одновременных запросов?!

Page 32: JavaScript. Event Loop and Timers (in russian)

32

Фрейм 0 выполняем код программы

Запрос к серверу

Список событий

Старт программы + Сейчас выполняется

Page 33: JavaScript. Event Loop and Timers (in russian)

33

Фрейм N пришел Запрос 1

Запрос к серверу Запрос к серверу

Список событий Сейчас выполняется

Файл прочитан 1 +

Page 34: JavaScript. Event Loop and Timers (in russian)

34

Фрейм N+1 пришел Запрос 2

Запрос к серверу Запрос к серверу

Список событий Сейчас выполняется

Файл прочитан 1

Файл прочитан 2 +

Page 35: JavaScript. Event Loop and Timers (in russian)

35

Фрейм N+2 прочитался Файл 1

Запрос к серверу

Список событий Сейчас выполняется

Файл прочитан 1

Файл прочитан 2

+ Файл отправлен 1

Файл отправлен 1 +

Page 36: JavaScript. Event Loop and Timers (in russian)

36

Фрейм N+3 еще Запрос 3

Запрос к серверу

Список событий Сейчас выполняется

Файл прочитан 2

Файл отправлен 1

Файл отправлен 1

Запрос к серверу

Файл прочитан 3 +

Page 37: JavaScript. Event Loop and Timers (in russian)

37

Фрейм N+4 Файлы 1 отправили

Запрос к серверу

Список событий Сейчас выполняется

Файл прочитан 2

Файл прочитан 3

Файл отправлен 1

Файл отправлен 1

Затем

Page 38: JavaScript. Event Loop and Timers (in russian)

38

Фрейм N+5 Файлы 2 прочитали

Запрос к серверу

Список событий Сейчас выполняется

Файл прочитан 3

Файл прочитан 2

+ Файл отправлен 2

Файл отправлен 2 +

Page 39: JavaScript. Event Loop and Timers (in russian)

39

Фрейм N+6 Файлы 3 прочитали

Запрос к серверу

Список событий Сейчас выполняется

Файл прочитан 3

Файл отправлен 2

Файл отправлен 2

+ Файл отправлен 3

Файл отправлен 3 +

Page 40: JavaScript. Event Loop and Timers (in russian)

40

Фрейм N+7 Файлы 3 отправили

Запрос к серверу

Список событий Сейчас выполняется

Файл отправлен 3

Файл отправлен 3

Затем Файл отправлен 2

Файл отправлен 2

Page 41: JavaScript. Event Loop and Timers (in russian)

41

Фрейм N+8 Файлы 2 отправили

Запрос к серверу

Список событий Сейчас выполняется

Файл отправлен 2

Файл отправлен 2

Затем

Page 42: JavaScript. Event Loop and Timers (in russian)

42

Фрейм N+100500 убираем обработчик Список событий

Убрать событие

Сейчас выполняется

Page 43: JavaScript. Event Loop and Timers (in russian)

43

Когда очередь пуста – программа завершается

Page 44: JavaScript. Event Loop and Timers (in russian)

44

Таймеры в JavaScript

Page 45: JavaScript. Event Loop and Timers (in russian)

45

Таймеры это не sleep() – это события во времени, они используют Event Loop

Page 46: JavaScript. Event Loop and Timers (in russian)

46

Таймер без повтора

•  setTimeout(function, timeout): Number –  выполни эту функцию не раньше чем через это время –  таймаут - миллисекунды

•  clearTimeout(timerId) –  предотврати выполнение этого таймера –  ид таймера – обычное число

Page 47: JavaScript. Event Loop and Timers (in russian)

47

setTimeout(function () { console.log(1); }, 1000); var timerId = setTimeout(function () { console.log(2); }, 1000); console.log(3); clearTimeout(timerId); // 3, 1

Пример setTimeout

Page 48: JavaScript. Event Loop and Timers (in russian)

48

Таймер c повтором

•  setInterval(function, timeout): Number –  выполняй эту функцию через данный интервал –  интервал - миллисекунды

•  clearInterval(timerId) –  предотврати выполнение этого интрвала –  ид интервала – обычное число

Page 49: JavaScript. Event Loop and Timers (in russian)

49

var times = 10; var intervalId = setInterval(function () { console.log(new Date()); times--; if (!times) { clearInterval(intervalId); } }, 1000);

Пример setInterval

Page 50: JavaScript. Event Loop and Timers (in russian)

50

Любой таймер будет вызван не раньше указанного времени

Page 51: JavaScript. Event Loop and Timers (in russian)

51

var time = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); // Эта функция выполняется 1100 мсек thisFunctionTakes1100msec(); // 1102

Пример промаха таймера

Page 52: JavaScript. Event Loop and Timers (in russian)

52

JavaScript работает в одном потоке и не может прерывать обработчики

Page 53: JavaScript. Event Loop and Timers (in russian)

53

Что происходит

Получить текущее время

Подписаться на событие T+1000

Тяжелая функция (1100 мс)

Время

T+1000

Выполнение функции таймера

Запаздывание

Page 54: JavaScript. Event Loop and Timers (in russian)

54

Таймеры выполняются в том же потоке, что и программа

Page 55: JavaScript. Event Loop and Timers (in russian)

55

var time = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); setTimeout(function () { // Эта функция выполняется 1100 мсек thisFunctionTakes1100msec(); }, 10); thisFunctionTakes1100msec(); // 2212 = 1100 + 10 + 1100 + x

Еще один пример промаха таймера

Page 56: JavaScript. Event Loop and Timers (in russian)

56

Таймер может никогда не выполниться

Page 57: JavaScript. Event Loop and Timers (in russian)

57

var time = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); while(true);

Пример не достижимого таймера

Page 58: JavaScript. Event Loop and Timers (in russian)

58

Время I/O > Время вычислений

Лучше Event Loop

Page 59: JavaScript. Event Loop and Timers (in russian)

59

Время I/O < Время вычислений

Лучше Thread или Fork

Page 60: JavaScript. Event Loop and Timers (in russian)

60

Работа с сервером

Page 61: JavaScript. Event Loop and Timers (in russian)

61

Асинхронная работа с сервером

Page 62: JavaScript. Event Loop and Timers (in russian)

62

AJAX – Асинхронный JavaScript и XML

Page 63: JavaScript. Event Loop and Timers (in russian)

63

Много разных API и хаков

• XMLHttpRequest • EventSource • WebSockets •  JSONP

Page 64: JavaScript. Event Loop and Timers (in russian)

64

XMLHttpRequest aka XHR

• Предполагали использовать XML • Победил JSON • XML остался

Page 65: JavaScript. Event Loop and Timers (in russian)

65

Возможности XMLHttpRequest

• Неблокирующие запросы –  GET, POST, PUT, DELETE, … –  Можно отправлять и блокирующие

• Нельзя отправлять на другой сервер –  В версии 2 можно

Page 66: JavaScript. Event Loop and Timers (in russian)

66

// GET запрос var xhr = new XMLHttpRequest(); // Подготавливаем запрос xhr.open('GET', 'http://server.ru/file.jpg', true); // Подписываемся на событие "изменение статуса" xhr.addEventListener('readystatechange', function () { // Когда ответ пришел if (xhr.readyState === 4) { // Печатаем тело ответа console.log(xhr.responseText); } }, false); // Отправляем запрос xhr.send();

Работа с XHR

Page 67: JavaScript. Event Loop and Timers (in russian)

67

Статусы XMLHttpRequest

• UNSENT=0 –  функция open() еще не вызвана

• OPENED=1 –  функция send() еще не вызвана

• HEADERS_RECEIVED=2 –  Пришли заголовки

• LOADING=3 –  часть ответа пришла

• DONE=4 –  запрос завершен

https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest

Page 68: JavaScript. Event Loop and Timers (in russian)

68

Методы и свойства XHR • open(method, url, isNotBlock)

–  method – 'get', 'post', … –  url – 'http://pewpew.com', '/file.jpg', 'file.jpg', '//site.ru:8080/'

• send(body) –  body – post тело 'name=name&time=1345678&message=hello'

• readyState: Number • responseText: String • status: Number

–  HTTP статус ответа – 200, 404, 500

• addEventListener(event, function) • ...

https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest

Page 69: JavaScript. Event Loop and Timers (in russian)

69

Сделаем обертку над XMLHttpRequest

Асинхронный XHR

function asyncXHR(method, url, data, callback) { var xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.addEventListener('readystatechange', function () { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(null, xhr.responseText); } else { callback('error'); } } }); xhr.send(data); }

Page 70: JavaScript. Event Loop and Timers (in russian)

70

Когда статус изменится – вызови эту функцию

Асинхронный XHR

function asyncXHR(method, url, data, callback) { var xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.addEventListener('readystatechange', function () { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(null, xhr.responseText); } else { callback('error'); } } }); xhr.send(data); }

Page 71: JavaScript. Event Loop and Timers (in russian)

71

Если статус = "Готово" – проверяем статус ответа

Асинхронный XHR

function asyncXHR(method, url, data, callback) { var xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.addEventListener('readystatechange', function () { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(null, xhr.responseText); } else { callback('error'); } } }); xhr.send(data); }

Page 72: JavaScript. Event Loop and Timers (in russian)

72

Если статус ответа 200 (все хорошо) – вызываем функцию с данными

Асинхронный XHR

function asyncXHR(method, url, data, callback) { var xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.addEventListener('readystatechange', function () { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(null, xhr.responseText); } else { callback('error'); } } }); xhr.send(data); }

Page 73: JavaScript. Event Loop and Timers (in russian)

73

Используем

asyncXHR('get', 'http://site.ru', null, function (err, data) { if (!err) { console.log(data); } });

Стало на много меньше кода

Page 74: JavaScript. Event Loop and Timers (in russian)

74

Перепишем наш абстрактный пример

asyncXHR('get', 'filename.jpg', null, processThenSendFile); function processThenSendFile(err, file) { file = jpg2png(file); asyncXHR('post', '//site.ru/', file, alertWhenDone); } function alertWhenDone(err, status) { alert('tada'); }

Page 75: JavaScript. Event Loop and Timers (in russian)

75

Заключение

• Линейная программа –  треды –  форки –  потоки

• Событийная программа –  Любой I/O – событие

• Event Loop • Таймеры • Асинхронная работа с сервером

–  AJAX –  XMLHttpRequest aka XHR

Page 76: JavaScript. Event Loop and Timers (in russian)

76

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

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

[email protected] azproduction

Спасибо