SlideShare a Scribd company logo
JavaScript. Event Loop and Timers (in russian)
Михаил Давыдов
Разработчик JavaScript
Асинхронность,
работа с
сервером
3
Задача
•  Качаем 1 файл
•  Обрабатываем
•  После отправляем данные на 2 сервера
•  Вызываем alert()
4
Псевдокод программы
var file = getFile('/filename.jpg');
file = jpg2png(file);
sendFile(file, 'http://server1.ru/');
sendFile(file, 'http://server2.ru/');
alert('tada!');
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 запроса
Получение данных
…
6
2. Обработка
var file = getFile('/filename.jpg');
file = jpg2png(file);
sendFile(file, 'http://server1.ru/');
sendFile(file, 'http://server2.ru/');
alert('tada!');
Переделываем JPG в PNG
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 запроса
Получение данных
…
8
4. Алерт
var file = getFile('/filename.jpg');
file = jpg2png(file);
sendFile(file, 'http://server1.ru/');
sendFile(file, 'http://server2.ru/');
alert('tada!');
Рисуем окно через системное API
9
Схема загрузки линейной программы
время
БлокировкаБлокировка Блокировка
Загрузка Отправка Отправка
Подготовка Обработка Отправка Алерт
10
Большую часть времени эта
программа ждет I/O
11
Стоимость операций I/O
• L1-кэш 3 цикла
• L2-кэш 14 циклов
• RAM 250 циклов
• Диск 41 000 000 циклов
• Сеть 240 000 000
12
На помощь приходят: треды,
потоки, форки…
13
дедлоки, мьютексы,
проблемы с синхронизацией
и параллельное
программирование
14
Событийная программа
16
Идея событийного программирования
•  Любое действие – событие
–  Начало программы
–  Клик на кнопку
–  Событие во времени
–  Конец чтения файла…
•  Программа не ждет I/O
–  Загрузка процесса предельно близка к 100%
•  Подписывается на события I/O
•  Выполняет код, когда событие наступило
17
Сообщи мне когда придет
файл, а пока я буду делать
что-то полезное
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!');
});
});
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!');
});
});
Когда файл скачается вызови эту функцию
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
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!');
});
});
Когда файлы отправятся вызови эту функцию
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!');
});
});
Рисуем системное окно
23
Схема загрузки событийной программы
время
Ожидание Ожидание
Запрос
Подготовка Обработка Отправка Алерт
24
Профит
•  Блокировка → Ожидание запроса
•  Программа не блокируется
•  Отправляет файлы параллельно
•  1 тред может обслуживать несколько
соединений
25
Event Loop
26
Event Loop
•  Один поток
•  Использует системные команды
–  *NIX: select, epoll, kqueue
–  Win: GetMessage, PeekMessage
•  Основа – список событий
•  Подписываемся на событие
•  Выполняем код, когда событие произошло
•  Список событий пуст – конец
27
Кадр или Фрейм Event Loop
=== обработчик события
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!');
});
});
Список событий
Когда придет запрос к серверу – запусти этот код
Запрос к серверу
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!');
});
});
Список событий
Пришел запрос к северу, выполняем обработчик
Когда файл прочитается – запусти этот код
Файл прочитан
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!');
});
});
Список событий
Файл прочитался, выполняем обработчик
Когда файлы отправятся – запусти этот код
Файл отправлен
Файл отправлен
31
А что если будет несколько
одновременных запросов?!
32
Фрейм 0 выполняем код программы
Запрос к серверу
Список событий
Старт программы +	

Сейчас выполняется
33
Фрейм N пришел Запрос 1
Запрос к серверу Запрос к серверу
Список событийСейчас выполняется
Файл прочитан 1+
34
Фрейм N+1 пришел Запрос 2
Запрос к серверу Запрос к серверу
Список событийСейчас выполняется
Файл прочитан 1
Файл прочитан 2+
35
Фрейм N+2 прочитался Файл 1
Запрос к серверу
Список событийСейчас выполняется
Файл прочитан 1
Файл прочитан 2
+	

 Файл отправлен 1
Файл отправлен 1+
36
Фрейм N+3 еще Запрос 3
Запрос к серверу
Список событийСейчас выполняется
Файл прочитан 2
Файл отправлен 1
Файл отправлен 1
Запрос к серверу
Файл прочитан 3+
37
Фрейм N+4 Файлы 1 отправили
Запрос к серверу
Список событийСейчас выполняется
Файл прочитан 2
Файл прочитан 3
Файл отправлен 1
Файл отправлен 1
Затем
38
Фрейм N+5 Файлы 2 прочитали
Запрос к серверу
Список событийСейчас выполняется
Файл прочитан 3
Файл прочитан 2
+	

 Файл отправлен 2
Файл отправлен 2+
39
Фрейм N+6 Файлы 3 прочитали
Запрос к серверу
Список событийСейчас выполняется
Файл прочитан 3
Файл отправлен 2
Файл отправлен 2
+	

 Файл отправлен 3
Файл отправлен 3+
40
Фрейм N+7 Файлы 3 отправили
Запрос к серверу
Список событийСейчас выполняется
Файл отправлен 3
Файл отправлен 3
Затем
Файл отправлен 2
Файл отправлен 2
41
Фрейм N+8 Файлы 2 отправили
Запрос к серверу
Список событийСейчас выполняется
Файл отправлен 2
Файл отправлен 2
Затем
42
Фрейм N+100500 убираем обработчик
Список событий
Убрать событие
Сейчас выполняется
43
Когда очередь пуста –
программа завершается
44
Таймеры в JavaScript
45
Таймеры это не sleep() –
это события во времени,
они используют Event Loop
46
Таймер без повтора
•  setTimeout(function, timeout): Number
–  выполни эту функцию не раньше чем через это время
–  таймаут - миллисекунды
•  clearTimeout(timerId)
–  предотврати выполнение этого таймера
–  ид таймера – обычное число
47
setTimeout(function () {
console.log(1);
}, 1000);
var timerId = setTimeout(function () {
console.log(2);
}, 1000);
console.log(3);
clearTimeout(timerId);
// 3, 1
Пример setTimeout
48
Таймер c повтором
•  setInterval(function, timeout): Number
–  выполняй эту функцию через данный интервал
–  интервал - миллисекунды
•  clearInterval(timerId)
–  предотврати выполнение этого интрвала
–  ид интервала – обычное число
49
var times = 10;
var intervalId = setInterval(function () {
console.log(new Date());
times--;
if (!times) {
clearInterval(intervalId);
}
}, 1000);
Пример setInterval
50
Любой таймер будет вызван
не раньше указанного
времени
51
var time = new Date();
setTimeout(function () {
console.log(new Date() - time);
}, 1000);
// Эта функция выполняется 1100 мсек
thisFunctionTakes1100msec();
// 1102
Пример промаха таймера
52
JavaScript работает
в одном потоке и не может
прерывать обработчики
53
Что происходит
Получить текущее время
Подписаться на событие T+1000
Тяжелая функция (1100 мс)
Время
T+1000
Выполнение функции таймера
Запаздывание
54
Таймеры выполняются в
том же потоке, что и
программа
55
var time = new Date();
setTimeout(function () {
console.log(new Date() - time);
}, 1000);
setTimeout(function () {
// Эта функция выполняется 1100 мсек
thisFunctionTakes1100msec();
}, 10);
thisFunctionTakes1100msec();
// 2212 = 1100 + 10 + 1100 + x
Еще один пример промаха таймера
56
Таймер может никогда не
выполниться
57
var time = new Date();
setTimeout(function () {
console.log(new Date() - time);
}, 1000);
while(true);
Пример не достижимого таймера
58
Время I/O > Время вычислений
Лучше Event Loop
59
Время I/O < Время вычислений
Лучше Thread или Fork
60
Работа с сервером
61
Асинхронная работа с
сервером
62
AJAX – Асинхронный
JavaScript и XML
63
Много разных API и хаков
•  XMLHttpRequest
•  EventSource
•  WebSockets
•  JSONP
64
XMLHttpRequest aka XHR
•  Предполагали использовать XML
•  Победил JSON
•  XML остался
65
Возможности XMLHttpRequest
•  Неблокирующие запросы
–  GET, POST, PUT, DELETE, …
–  Можно отправлять и блокирующие
•  Нельзя отправлять на другой сервер
–  В версии 2 можно
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
67
Статусы XMLHttpRequest
•  UNSENT=0
–  функция open() еще не вызвана
•  OPENED=1
–  функция send() еще не вызвана
•  HEADERS_RECEIVED=2
–  Пришли заголовки
•  LOADING=3
–  часть ответа пришла
•  DONE=4
–  запрос завершен
https://developer.mozilla.org/en-US/docs/DOM/
XMLHttpRequest
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
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);
}
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);
}
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);
}
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);
}
73
Используем
asyncXHR('get', 'http://site.ru', null,
function (err, data) {
if (!err) {
console.log(data);
}
});
Стало на много меньше кода
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');
}
75
Заключение
•  Линейная программа
–  треды
–  форки
–  потоки
•  Событийная программа
–  Любой I/O – событие
•  Event Loop
•  Таймеры
•  Асинхронная работа с сервером
–  AJAX
–  XMLHttpRequest aka XHR
76
Михаил Давыдов
Разработчик JavaScript
azproduction@yandex-team.ru
azproduction
Спасибо

More Related Content

PDF
Михаил Давыдов: JavaScript. Асинхронность
PDF
PDF
Практика Lock-free. RealTime-сервер
PDF
Григорий Демченко — Асинхронное программирование и сопрограммы
PDF
JavaDay'14
PDF
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
PPTX
Multithreading in java past and actual
PDF
RxJava+RxAndroid (Lecture 20 – rx java)
Михаил Давыдов: JavaScript. Асинхронность
Практика Lock-free. RealTime-сервер
Григорий Демченко — Асинхронное программирование и сопрограммы
JavaDay'14
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Multithreading in java past and actual
RxJava+RxAndroid (Lecture 20 – rx java)

What's hot (20)

PDF
Библиотеки для передачи данных (Lecture 13 – multithreading, network (libs))
PPTX
Производительность open source решений
PDF
Помоги ближнему, или Как потоки помогают друг другу
PPTX
Java 8. Thread pools
PPTX
Java threads - part 2
PPTX
Java threads - part 3
PDF
Киллер-фича языка C# — конструкция async/await
PPTX
Java threads - part 1
PDF
Android - 11 - Multithreading
PDF
Java 9: what is there beyond modularization
PPTX
Service Discovery. More that it seems
PDF
PostgreSQL Streaming Replication
PDF
Сергей Еланцев - Troubleshooting
PDF
Java tricks for high-load server programming
PPTX
Тестирование производительности систем мониторинга на платформе Microsoft SCO...
PDF
Многопоточное программирование на C#, путевые заметки
PDF
Atomics, CAS and Nonblocking algorithms
PDF
Михаил Давыдов - JavaScript. Асинхронность
PPTX
Developing highload servers with Java
PDF
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
Библиотеки для передачи данных (Lecture 13 – multithreading, network (libs))
Производительность open source решений
Помоги ближнему, или Как потоки помогают друг другу
Java 8. Thread pools
Java threads - part 2
Java threads - part 3
Киллер-фича языка C# — конструкция async/await
Java threads - part 1
Android - 11 - Multithreading
Java 9: what is there beyond modularization
Service Discovery. More that it seems
PostgreSQL Streaming Replication
Сергей Еланцев - Troubleshooting
Java tricks for high-load server programming
Тестирование производительности систем мониторинга на платформе Microsoft SCO...
Многопоточное программирование на C#, путевые заметки
Atomics, CAS and Nonblocking algorithms
Михаил Давыдов - JavaScript. Асинхронность
Developing highload servers with Java
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
Ad

Similar to JavaScript. Event Loop and Timers (in russian) (20)

PPTX
Асинхронность и сопрограммы
PPTX
Использование Open Source инструментов для автоматизации тестирования
PPTX
Операционные системы 2015, лекция № 4
PDF
Леонид Васильев "Python в инфраструктуре поиска"
PDF
Froglogic Squish
PDF
JPoint 2016 - Etudes of DIY Java profiler
PPT
ВВЕДЕНИЕ В NODE.JS
PDF
Автоматизация задач с помощью EEM
PDF
Алексей Андросов "Яндекс.Почта: архитектура фронтенда как она есть"
PPTX
PowerShell
PDF
Веб-сервер Phantom
PDF
Асинхронный JavaScript
PPT
8. java lecture threads
PPTX
Tdd webpack + testem + mocha + chai
PDF
Linux Kernel Processes
PDF
Java осень 2013 лекция 6
PDF
Introduction in Node.js (in russian)
PDF
SECON'2017, Лесовский Алексей, Потоковая репликация в PostgreSQL.
PPTX
Luxoft async.net
PPTX
Асинхронность и сопрограммы
Использование Open Source инструментов для автоматизации тестирования
Операционные системы 2015, лекция № 4
Леонид Васильев "Python в инфраструктуре поиска"
Froglogic Squish
JPoint 2016 - Etudes of DIY Java profiler
ВВЕДЕНИЕ В NODE.JS
Автоматизация задач с помощью EEM
Алексей Андросов "Яндекс.Почта: архитектура фронтенда как она есть"
PowerShell
Веб-сервер Phantom
Асинхронный JavaScript
8. java lecture threads
Tdd webpack + testem + mocha + chai
Linux Kernel Processes
Java осень 2013 лекция 6
Introduction in Node.js (in russian)
SECON'2017, Лесовский Алексей, Потоковая репликация в PostgreSQL.
Luxoft async.net
Ad

More from Mikhail Davydov (15)

PDF
Components now! (in russian)
PDF
JavaScript. Event Model (in russian)
PDF
Code Style (in russian)
PDF
Ajax and Transports (in russian)
PDF
JavaScript. Loops and functions (in russian)
PDF
JavaScript. OOP (in russian)
PDF
Modules and assembling of JavaScript (in russian)
PDF
JavaScript. Introduction (in russian)
PDF
JavaScript. Basics (in russian)
PDF
JavaScript. Async (in Russian)
PDF
JavaScript on frontend and backend (in Russian
PDF
Components now!
PDF
Dump-IT Загрузка и инициализация JavaScript
PDF
Dart - светлая сторона силы?
PDF
Making Scalable JavaScript Application
Components now! (in russian)
JavaScript. Event Model (in russian)
Code Style (in russian)
Ajax and Transports (in russian)
JavaScript. Loops and functions (in russian)
JavaScript. OOP (in russian)
Modules and assembling of JavaScript (in russian)
JavaScript. Introduction (in russian)
JavaScript. Basics (in russian)
JavaScript. Async (in Russian)
JavaScript on frontend and backend (in Russian
Components now!
Dump-IT Загрузка и инициализация JavaScript
Dart - светлая сторона силы?
Making Scalable JavaScript Application

JavaScript. Event Loop and Timers (in russian)

  • 3. 3 Задача •  Качаем 1 файл •  Обрабатываем •  После отправляем данные на 2 сервера •  Вызываем alert()
  • 4. 4 Псевдокод программы var file = getFile('/filename.jpg'); file = jpg2png(file); sendFile(file, 'http://server1.ru/'); sendFile(file, 'http://server2.ru/'); alert('tada!');
  • 5. 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 запроса Получение данных …
  • 6. 6 2. Обработка var file = getFile('/filename.jpg'); file = jpg2png(file); sendFile(file, 'http://server1.ru/'); sendFile(file, 'http://server2.ru/'); alert('tada!'); Переделываем JPG в PNG
  • 7. 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 запроса Получение данных …
  • 8. 8 4. Алерт var file = getFile('/filename.jpg'); file = jpg2png(file); sendFile(file, 'http://server1.ru/'); sendFile(file, 'http://server2.ru/'); alert('tada!'); Рисуем окно через системное API
  • 9. 9 Схема загрузки линейной программы время БлокировкаБлокировка Блокировка Загрузка Отправка Отправка Подготовка Обработка Отправка Алерт
  • 10. 10 Большую часть времени эта программа ждет I/O
  • 11. 11 Стоимость операций I/O • L1-кэш 3 цикла • L2-кэш 14 циклов • RAM 250 циклов • Диск 41 000 000 циклов • Сеть 240 000 000
  • 12. 12 На помощь приходят: треды, потоки, форки…
  • 13. 13 дедлоки, мьютексы, проблемы с синхронизацией и параллельное программирование
  • 14. 14
  • 16. 16 Идея событийного программирования •  Любое действие – событие –  Начало программы –  Клик на кнопку –  Событие во времени –  Конец чтения файла… •  Программа не ждет I/O –  Загрузка процесса предельно близка к 100% •  Подписывается на события I/O •  Выполняет код, когда событие наступило
  • 17. 17 Сообщи мне когда придет файл, а пока я буду делать что-то полезное
  • 18. 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!'); }); });
  • 19. 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!'); }); }); Когда файл скачается вызови эту функцию
  • 20. 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
  • 21. 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!'); }); }); Когда файлы отправятся вызови эту функцию
  • 22. 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!'); }); }); Рисуем системное окно
  • 23. 23 Схема загрузки событийной программы время Ожидание Ожидание Запрос Подготовка Обработка Отправка Алерт
  • 24. 24 Профит •  Блокировка → Ожидание запроса •  Программа не блокируется •  Отправляет файлы параллельно •  1 тред может обслуживать несколько соединений
  • 26. 26 Event Loop •  Один поток •  Использует системные команды –  *NIX: select, epoll, kqueue –  Win: GetMessage, PeekMessage •  Основа – список событий •  Подписываемся на событие •  Выполняем код, когда событие произошло •  Список событий пуст – конец
  • 27. 27 Кадр или Фрейм Event Loop === обработчик события
  • 28. 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!'); }); }); Список событий Когда придет запрос к серверу – запусти этот код Запрос к серверу
  • 29. 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!'); }); }); Список событий Пришел запрос к северу, выполняем обработчик Когда файл прочитается – запусти этот код Файл прочитан
  • 30. 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!'); }); }); Список событий Файл прочитался, выполняем обработчик Когда файлы отправятся – запусти этот код Файл отправлен Файл отправлен
  • 31. 31 А что если будет несколько одновременных запросов?!
  • 32. 32 Фрейм 0 выполняем код программы Запрос к серверу Список событий Старт программы + Сейчас выполняется
  • 33. 33 Фрейм N пришел Запрос 1 Запрос к серверу Запрос к серверу Список событийСейчас выполняется Файл прочитан 1+
  • 34. 34 Фрейм N+1 пришел Запрос 2 Запрос к серверу Запрос к серверу Список событийСейчас выполняется Файл прочитан 1 Файл прочитан 2+
  • 35. 35 Фрейм N+2 прочитался Файл 1 Запрос к серверу Список событийСейчас выполняется Файл прочитан 1 Файл прочитан 2 + Файл отправлен 1 Файл отправлен 1+
  • 36. 36 Фрейм N+3 еще Запрос 3 Запрос к серверу Список событийСейчас выполняется Файл прочитан 2 Файл отправлен 1 Файл отправлен 1 Запрос к серверу Файл прочитан 3+
  • 37. 37 Фрейм N+4 Файлы 1 отправили Запрос к серверу Список событийСейчас выполняется Файл прочитан 2 Файл прочитан 3 Файл отправлен 1 Файл отправлен 1 Затем
  • 38. 38 Фрейм N+5 Файлы 2 прочитали Запрос к серверу Список событийСейчас выполняется Файл прочитан 3 Файл прочитан 2 + Файл отправлен 2 Файл отправлен 2+
  • 39. 39 Фрейм N+6 Файлы 3 прочитали Запрос к серверу Список событийСейчас выполняется Файл прочитан 3 Файл отправлен 2 Файл отправлен 2 + Файл отправлен 3 Файл отправлен 3+
  • 40. 40 Фрейм N+7 Файлы 3 отправили Запрос к серверу Список событийСейчас выполняется Файл отправлен 3 Файл отправлен 3 Затем Файл отправлен 2 Файл отправлен 2
  • 41. 41 Фрейм N+8 Файлы 2 отправили Запрос к серверу Список событийСейчас выполняется Файл отправлен 2 Файл отправлен 2 Затем
  • 42. 42 Фрейм N+100500 убираем обработчик Список событий Убрать событие Сейчас выполняется
  • 43. 43 Когда очередь пуста – программа завершается
  • 45. 45 Таймеры это не sleep() – это события во времени, они используют Event Loop
  • 46. 46 Таймер без повтора •  setTimeout(function, timeout): Number –  выполни эту функцию не раньше чем через это время –  таймаут - миллисекунды •  clearTimeout(timerId) –  предотврати выполнение этого таймера –  ид таймера – обычное число
  • 47. 47 setTimeout(function () { console.log(1); }, 1000); var timerId = setTimeout(function () { console.log(2); }, 1000); console.log(3); clearTimeout(timerId); // 3, 1 Пример setTimeout
  • 48. 48 Таймер c повтором •  setInterval(function, timeout): Number –  выполняй эту функцию через данный интервал –  интервал - миллисекунды •  clearInterval(timerId) –  предотврати выполнение этого интрвала –  ид интервала – обычное число
  • 49. 49 var times = 10; var intervalId = setInterval(function () { console.log(new Date()); times--; if (!times) { clearInterval(intervalId); } }, 1000); Пример setInterval
  • 50. 50 Любой таймер будет вызван не раньше указанного времени
  • 51. 51 var time = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); // Эта функция выполняется 1100 мсек thisFunctionTakes1100msec(); // 1102 Пример промаха таймера
  • 52. 52 JavaScript работает в одном потоке и не может прерывать обработчики
  • 53. 53 Что происходит Получить текущее время Подписаться на событие T+1000 Тяжелая функция (1100 мс) Время T+1000 Выполнение функции таймера Запаздывание
  • 54. 54 Таймеры выполняются в том же потоке, что и программа
  • 55. 55 var time = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); setTimeout(function () { // Эта функция выполняется 1100 мсек thisFunctionTakes1100msec(); }, 10); thisFunctionTakes1100msec(); // 2212 = 1100 + 10 + 1100 + x Еще один пример промаха таймера
  • 56. 56 Таймер может никогда не выполниться
  • 57. 57 var time = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); while(true); Пример не достижимого таймера
  • 58. 58 Время I/O > Время вычислений Лучше Event Loop
  • 59. 59 Время I/O < Время вычислений Лучше Thread или Fork
  • 63. 63 Много разных API и хаков •  XMLHttpRequest •  EventSource •  WebSockets •  JSONP
  • 64. 64 XMLHttpRequest aka XHR •  Предполагали использовать XML •  Победил JSON •  XML остался
  • 65. 65 Возможности XMLHttpRequest •  Неблокирующие запросы –  GET, POST, PUT, DELETE, … –  Можно отправлять и блокирующие •  Нельзя отправлять на другой сервер –  В версии 2 можно
  • 66. 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
  • 67. 67 Статусы XMLHttpRequest •  UNSENT=0 –  функция open() еще не вызвана •  OPENED=1 –  функция send() еще не вызвана •  HEADERS_RECEIVED=2 –  Пришли заголовки •  LOADING=3 –  часть ответа пришла •  DONE=4 –  запрос завершен https://developer.mozilla.org/en-US/docs/DOM/ XMLHttpRequest
  • 68. 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
  • 69. 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); }
  • 70. 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); }
  • 71. 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); }
  • 72. 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); }
  • 73. 73 Используем asyncXHR('get', 'http://site.ru', null, function (err, data) { if (!err) { console.log(data); } }); Стало на много меньше кода
  • 74. 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'); }
  • 75. 75 Заключение •  Линейная программа –  треды –  форки –  потоки •  Событийная программа –  Любой I/O – событие •  Event Loop •  Таймеры •  Асинхронная работа с сервером –  AJAX –  XMLHttpRequest aka XHR