Михаил Давыдов: JavaScript. Асинхронность
Upcoming SlideShare
Loading in...5
×
 

Михаил Давыдов: JavaScript. Асинхронность

on

  • 2,121 views

 

Statistics

Views

Total Views
2,121
Views on SlideShare
458
Embed Views
1,663

Actions

Likes
3
Downloads
4
Comments
0

3 Embeds 1,663

http://tech.yandex.ru 1504
https://tech.yandex.ru 157
http://news.google.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Михаил Давыдов: JavaScript. Асинхронность Михаил Давыдов: JavaScript. Асинхронность Presentation Transcript

  • JavaScript Асинхронность Михаил Давыдов Разработчик JavaScript
  • Задача •  Качаем 1 файл •  После отправляем данные на 2 сервера •  Синхронизируемся 3
  • Синхронный код Сделаем обертку над XMLHttpRequest function syncXHR(method, url, data) { var xhr = new XMLHttpRequest(); xhr.open(method, url, false); xhr.send(data); return xhr.responseText; } var data = syncXHR('GET', 'http://host1/page.json'); data = processData(data); syncXHR('POST', 'http://host2/result/', data); syncXHR('POST', 'http://host3/result/', data); alert('Done!'); 4 View slide
  • Схема загрузки Обработка Подготовка Отправка Алерт Блокировка Блокировка Запрос 5 Блокировка Запрос Запрос время View slide
  • Асинхронный код Сделаем обертку над XMLHttpRequest function asyncXHR(method, url, data, callback) { var xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(null, xhr.responseText); } else { callback(‘error’); } } } xhr.send(data); } 6
  • Асинхронный код Сам код. Изменилось все. asyncXHR ('GET', ‘http://host1/page.json’, null, function (err, data) { data = processData(data); var counter = 2; function done(err, data) { counter--; if (!counter) alert(‘Done!’); } asyncXHR(‘POST’, ‘http://host2/result/’, data, done); asyncXHR(‘POST’, ‘http://host3/result/’, data, done); }); 7
  • Схема загрузки Обработка Отправка Подготовка Ожидание Алерт Ожидание Запрос 8 время
  • Где применяется "асинхронность" •  Производительность •  Интерфейс пользователя •  Проблемы –  Много лишнего шума –  Проблема синхронизации –  Куча вложенных колбэков: Pyramid of Doom •  Несколько реализаций –  Event Loop 9
  • Event Loop 10
  • Event Loop •  Основа всех событийных систем •  Использует очередь событий •  Ждет события •  Выполняет события из очереди –  События в очередь поступают во время выполнения событий –  События генерируют события •  Завершается когда очередь пуста 11
  • 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!'); }); }); 12 Запрос к серверу
  • 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!'); }); }); 13 Файл прочитан
  • 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!'); }); }); 14 Файл отправлен Файл отправлен
  • А что если будет несколько одновременных запросов?! 15
  • Фрейм 0 выполняем код программы Сейчас выполняется Старт программы 16 Список событий + Запрос к серверу
  • Фрейм N пришел Запрос 1 Сейчас выполняется Список событий Запрос к серверу Запрос к серверу + 17 Файл прочитан 1
  • Фрейм N+1 пришел Запрос 2 Сейчас выполняется Список событий Запрос к серверу Запрос к серверу Файл прочитан 1 + 18 Файл прочитан 2
  • Фрейм N+2 прочитался Файл 1 Сейчас выполняется Список событий Файл прочитан 1 Запрос к серверу Файл прочитан 2 + + 19 Файл отправлен 1 Файл отправлен 1
  • Фрейм N+3 еще Запрос 3 Сейчас выполняется Список событий Запрос к серверу Запрос к серверу Файл прочитан 2 Файл отправлен 1 Файл отправлен 1 + 20 Файл прочитан 3
  • Фрейм N+4 Файлы 1 отправили Сейчас выполняется Файл отправлен 1 Затем Файл отправлен 1 Список событий Запрос к серверу Файл прочитан 2 Файл прочитан 3 21
  • Фрейм N+5 Файлы 2 прочитали Сейчас выполняется Список событий Файл прочитан 2 Запрос к серверу Файл прочитан 3 + + 22 Файл отправлен 2 Файл отправлен 2
  • Фрейм N+6 Файлы 3 прочитали Сейчас выполняется Список событий Файл прочитан 3 Запрос к серверу Файл отправлен 2 Файл отправлен 2 + + 23 Файл отправлен 3 Файл отправлен 3
  • Фрейм N+7 Файлы 3 отправили Сейчас выполняется Файл отправлен 3 Затем Файл отправлен 3 Список событий Запрос к серверу Файл отправлен 2 Файл отправлен 2 24
  • Фрейм N+8 Файлы 2 отправили Сейчас выполняется Файл отправлен 2 Затем Файл отправлен 2 25 Список событий Запрос к серверу
  • Фрейм N+100500 убираем обработчик Сейчас выполняется Убрать событие 26 Список событий
  • Когда очередь пуста – программа завершается 27
  • Таймеры в JavaScript 28
  • Таймеры это не sleep() – это события во времени, они используют Event Loop 29
  • Таймер без повтора •  setTimeout(function, timeout): Number –  выполни эту функцию не раньше чем через это время –  таймаут - миллисекунды •  clearTimeout(timerId) –  предотврати выполнение этого таймера –  ид таймера – обычное число 30
  • Таймер c повтором •  setInterval(function, timeout): Number –  выполняй эту функцию через данный интервал –  интервал - миллисекунды •  clearInterval(timerId) –  предотврати выполнение этого интрвала –  ид интервала – обычное число 31
  • Любой таймер будет вызван не раньше указанного времени 32
  • Пример промаха таймера var time = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); // Эта функция выполняется 1100 мсек thisFunctionTakes1100msec(); // 1102 33
  • JavaScript работает в одном потоке и не может прерывать обработчики 34
  • Что происходит Время Получить текущее время Подписаться на событие T+1000 Тяжелая функция (1100 мс) T+1000 Запаздывание Выполнение функции таймера 35
  • Таймеры выполняются в том же потоке, что и программа 36
  • Еще один пример промаха таймера var time = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); setTimeout(function () { // Эта функция выполняется 1100 мсек thisFunctionTakes1100msec(); }, 10); thisFunctionTakes1100msec(); // 2212 = 1100 + 10 + 1100 + x 37
  • Таймер может никогда не выполниться 38
  • Пример недостижимого таймера var time = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); while(true); 39
  • Паттерны Callback, Event, Promise, Deferred
  • Callback Типичный пример – обертка над XMLHttpRequest function asyncXHR(method, url, data, callback) { var xhr = new XMLHttpRequest(); xhr.open(method, url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(null, xhr.responseText); } else { callback(‘error’); } } } xhr.send(data); } 41
  • Callback •  Самый простой вариант –  Дешевая абстракция •  В него могут приходить ошибки и данные –  cтиль node.js –  callback(err, data) 42
  • Event: EventEmitter, PubSub Общая схема function EventEmitter () { this.events = {}; } EventEmitter.prototype = { on: function (event, callback) {}, off: function (event, callback) {}, emit: function (event, data) {} }; 43 http://nodejs.org/api/events.html
  • Event Типичный пример – обертка над XMLHttpRequest function eventXHR(method, url, data) { var xhr = new XMLHttpRequest(), event = new EventEmitter(); xhr.open(method, url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { event.emit('data', xhr.responseText); } else { event.emit('error'); } } } xhr.send(data); return event; } 44
  • Event Сам код. Изменилось не так много. eventXHR('GET', 'http://host1/page.json') .on('data', function (data) { data = processData(data); var counter = 2; function done() { counter--; if (!counter) alert(‘Done!’); } eventXHR('POST', 'http://host2/result/', data) .on('data', done); eventXHR('POST', 'http://host3/result/', data) .on('data', done); }) .on('error', function(){ }); 45
  • Event •  Абстракция более высокого уровня •  Ошибки отделены от данных –  Возможны логически разные типы данных •  Можно отписаться от события •  Можно подписаться несколько раз •  Можно передавать как аргумент 46
  • Promise •  Это Обещанные данные •  Имеет 3 состояния –  Не выполнен (выполняется) –  Выполнен (результат) –  Отклонен (ошибка) •  Меняет состояние только 1 раз –  В событиях состояние меняется сколько угодно раз •  Запоминает свое состояние –  В отличии от события в котором состояние – это поток 47 http://wiki.commonjs.org/wiki/Promises
  • Promise Общая схема function Promise () { this.isFulfilled = false; this.isRejected = false; this.isResolved = false; this.result = null; } Promise.prototype = { then: function (fulfilled, rejected, progressed) {}, reject: function (error) {}, resolve: function (data) {} }; 48
  • Promise Типичный пример – обертка над XMLHttpRequest function promiseXHR(method, url, data) { var xhr = new XMLHttpRequest(), promise = new Promise(); xhr.open(method, url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { promise.resolve(xhr.responseText); } else { promise.reject('Error ' + xhr.status); } } } xhr.send(data); return promise; } 49
  • Promise Сам код promiseXHR('GET', 'http://host1/page.json') .then(function (data) { data = processData(data); var promises = [ promiseXHR('POST', 'http://host2/result/', data), promiseXHR('POST', 'http://host3/result/', data) ]; return when(promises); }) .then(function (data) { alert('Done!'); }) 50
  • Promise •  Запоминает свое состояние •  Всегда возвращает один результат –  В отличие от события где данные – поток –  Не зависит от времени опроса •  Можно передавать как аргумент •  Можно выполнять операции –  then 51
  • Deferred •  Это защищенный Promise •  Разграничивает слушателя и Promise •  Слушатель не может вмешаться –  С чистыми промисами можно завершить промис на слушателе –  Меньше логических ошибок 52 http://api.jquery.com/category/deferred-object/
  • Deferred Общая схема function Deferred () { this._promise = { then: function (fulfilled, rejected, progressed) {} }; } Deferred.prototype = { promise: function (error) { return this._promise; }, reject: function (error) {}, resolve: function (data) {} }; 53
  • Deferred Типичный пример – обертка над XMLHttpRequest function defferedXHR(method, url, data) { var xhr = new XMLHttpRequest(), deferred = new Deffered(); xhr.open(method, url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { deferred.resolve(xhr.responseText); } else { deferred.reject('Error ' + xhr.status); } } } xhr.send(data); return deferred.promise(); } 54
  • Deferred Сам код defferedXHR('GET', 'http://host1/page.json') .then(function (data) { data = processData(data); var promises = [ defferedXHR('POST', 'http://host2/result/', data), defferedXHR('POST', 'http://host3/result/', data) ]; when(promises, function (data) { alert('Done!'); }); }) .reject(‘Mua-ha-ha!’); // Это сделать нельзя 55
  • Библиотеки Streamlinejs, Step, Q
  • Streamline Streamline – попытка избавится от асинхронного шума Используют callback(err, data) var data = asyncXHR('GET', '/', null, _); asyncXHR('POST', '/', data, _); asyncXHR('POST', '/', data, _); alert('Done!'); 57 https://github.com/Sage/streamlinejs
  • Streamline – результат генерации Happy Debug! (function main(_) { var data; var __frame = { name: "main”, line: 1 }; return __func(_, this, arguments, main, 0, __frame, function __$main() { return asyncXHR("GET", "/", null, __cb(_, __frame, 17, 11, function ___(__0, __1) { data = __1; return asyncXHR("POST", "/", data, __cb(_, __frame, 18, 0, function __$main() { return asyncXHR("POST", "/", data, __cb(_, __frame, 19, 0, function __$main() { alert("Done!"); _(); }, true)); }, true)); }, true)); }); }).call(this, __trap); 58
  • Streamlinejs •  Генерация кода – результат ужасен! •  Шум из массы _ •  Его цель – выполнять асинхронный код последовательно 59
  • Step Позволяет выполнять асинхронный код в синхронном стиле Работает с callback(err, data) Step( function () { asyncXHR('GET', '...', null, this); }, function (err, data) { return processData(data); }, function (err, data) { asyncXHR('POST', '...', data, this.parallel()); asyncXHR('POST', '...', data, this.parallel()); }, function (err, result1, result2) { alert('Done!'); } ); 60 https://github.com/creationix/step
  • Q Работает с Promise Представляет интерфейс для работы с промисами var data = promiseXHR('GET', '...'); data.than(processAndSendData).than(function () { alert(‘Done!’); }); function processAndSendData(data) { data = processData(data); return sendData(data); } function sendData(data) { return Q.all([ promiseXHR('POST', '...', data), promiseXHR('POST', '...', data) ]); } 61 https://github.com/kriskowal/q
  • Асинхронность •  Событийный ввод-вывод •  Работа с GUI •  Паттерны –  Callback –  EventEmitter –  Promise –  Deferred •  Хаки –  Streamline –  Fibers •  Библиотеки –  Step –  Q 62
  • Михаил Давыдов Разработчик JavaScript azproduction@yandex-team.ru azproduction Спасибо