Top Banner
76

JavaScript. Event Loop and Timers (in russian)

Nov 29, 2014

Download

Technology

Mikhail Davydov

 
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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

Спасибо