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
Схема загрузки

Обработка

Подготовка

Отправка

Алерт

Блокировка

Блокировка

Запрос

5

Блокировка

Запрос

Запрос

время
Асинхронный код
Сделаем обертку над 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

Спасибо

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

  • 2.
  • 3.
    Задача •  Качаем 1файл •  После отправляем данные на 2 сервера •  Синхронизируемся 3
  • 4.
    Синхронный код Сделаем оберткунад 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
  • 5.
  • 6.
    Асинхронный код Сделаем оберткунад 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
  • 7.
    Асинхронный код Сам код.Изменилось все. 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.
  • 9.
    Где применяется "асинхронность" • Производительность •  Интерфейс пользователя •  Проблемы –  Много лишнего шума –  Проблема синхронизации –  Куча вложенных колбэков: Pyramid of Doom •  Несколько реализаций –  Event Loop 9
  • 10.
  • 11.
    Event Loop •  Основавсех событийных систем •  Использует очередь событий •  Ждет события •  Выполняет события из очереди –  События в очередь поступают во время выполнения событий –  События генерируют события •  Завершается когда очередь пуста 11
  • 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!'); }); }); 12 Запрос к серверу
  • 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!'); }); }); 13 Файл прочитан
  • 14.
    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.
    А что еслибудет несколько одновременных запросов?! 15
  • 16.
    Фрейм 0 выполняемкод программы Сейчас выполняется Старт программы 16 Список событий + Запрос к серверу
  • 17.
    Фрейм N пришелЗапрос 1 Сейчас выполняется Список событий Запрос к серверу Запрос к серверу + 17 Файл прочитан 1
  • 18.
    Фрейм N+1 пришелЗапрос 2 Сейчас выполняется Список событий Запрос к серверу Запрос к серверу Файл прочитан 1 + 18 Файл прочитан 2
  • 19.
    Фрейм N+2 прочиталсяФайл 1 Сейчас выполняется Список событий Файл прочитан 1 Запрос к серверу Файл прочитан 2 + + 19 Файл отправлен 1 Файл отправлен 1
  • 20.
    Фрейм N+3 ещеЗапрос 3 Сейчас выполняется Список событий Запрос к серверу Запрос к серверу Файл прочитан 2 Файл отправлен 1 Файл отправлен 1 + 20 Файл прочитан 3
  • 21.
    Фрейм N+4 Файлы1 отправили Сейчас выполняется Файл отправлен 1 Затем Файл отправлен 1 Список событий Запрос к серверу Файл прочитан 2 Файл прочитан 3 21
  • 22.
    Фрейм N+5 Файлы2 прочитали Сейчас выполняется Список событий Файл прочитан 2 Запрос к серверу Файл прочитан 3 + + 22 Файл отправлен 2 Файл отправлен 2
  • 23.
    Фрейм N+6 Файлы3 прочитали Сейчас выполняется Список событий Файл прочитан 3 Запрос к серверу Файл отправлен 2 Файл отправлен 2 + + 23 Файл отправлен 3 Файл отправлен 3
  • 24.
    Фрейм N+7 Файлы3 отправили Сейчас выполняется Файл отправлен 3 Затем Файл отправлен 3 Список событий Запрос к серверу Файл отправлен 2 Файл отправлен 2 24
  • 25.
    Фрейм N+8 Файлы2 отправили Сейчас выполняется Файл отправлен 2 Затем Файл отправлен 2 25 Список событий Запрос к серверу
  • 26.
    Фрейм N+100500 убираемобработчик Сейчас выполняется Убрать событие 26 Список событий
  • 27.
    Когда очередь пуста– программа завершается 27
  • 28.
  • 29.
    Таймеры это неsleep() – это события во времени, они используют Event Loop 29
  • 30.
    Таймер без повтора • setTimeout(function, timeout): Number –  выполни эту функцию не раньше чем через это время –  таймаут - миллисекунды •  clearTimeout(timerId) –  предотврати выполнение этого таймера –  ид таймера – обычное число 30
  • 31.
    Таймер c повтором • setInterval(function, timeout): Number –  выполняй эту функцию через данный интервал –  интервал - миллисекунды •  clearInterval(timerId) –  предотврати выполнение этого интрвала –  ид интервала – обычное число 31
  • 32.
    Любой таймер будетвызван не раньше указанного времени 32
  • 33.
    Пример промаха таймера vartime = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); // Эта функция выполняется 1100 мсек thisFunctionTakes1100msec(); // 1102 33
  • 34.
    JavaScript работает в одномпотоке и не может прерывать обработчики 34
  • 35.
    Что происходит Время Получить текущеевремя Подписаться на событие T+1000 Тяжелая функция (1100 мс) T+1000 Запаздывание Выполнение функции таймера 35
  • 36.
    Таймеры выполняются в томже потоке, что и программа 36
  • 37.
    Еще один примерпромаха таймера 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.
    Таймер может никогдане выполниться 38
  • 39.
    Пример недостижимого таймера vartime = new Date(); setTimeout(function () { console.log(new Date() - time); }, 1000); while(true); 39
  • 40.
  • 41.
    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
  • 42.
    Callback •  Самый простойвариант –  Дешевая абстракция •  В него могут приходить ошибки и данные –  cтиль node.js –  callback(err, data) 42
  • 43.
    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
  • 44.
    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
  • 45.
    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
  • 46.
    Event •  Абстракция болеевысокого уровня •  Ошибки отделены от данных –  Возможны логически разные типы данных •  Можно отписаться от события •  Можно подписаться несколько раз •  Можно передавать как аргумент 46
  • 47.
    Promise •  Это Обещанныеданные •  Имеет 3 состояния –  Не выполнен (выполняется) –  Выполнен (результат) –  Отклонен (ошибка) •  Меняет состояние только 1 раз –  В событиях состояние меняется сколько угодно раз •  Запоминает свое состояние –  В отличии от события в котором состояние – это поток 47 http://wiki.commonjs.org/wiki/Promises
  • 48.
    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
  • 49.
    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
  • 50.
    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
  • 51.
    Promise •  Запоминает своесостояние •  Всегда возвращает один результат –  В отличие от события где данные – поток –  Не зависит от времени опроса •  Можно передавать как аргумент •  Можно выполнять операции –  then 51
  • 52.
    Deferred •  Это защищенныйPromise •  Разграничивает слушателя и Promise •  Слушатель не может вмешаться –  С чистыми промисами можно завершить промис на слушателе –  Меньше логических ошибок 52 http://api.jquery.com/category/deferred-object/
  • 53.
    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
  • 54.
    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
  • 55.
    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
  • 56.
  • 57.
    Streamline Streamline – попыткаизбавится от асинхронного шума Используют callback(err, data) var data = asyncXHR('GET', '/', null, _); asyncXHR('POST', '/', data, _); asyncXHR('POST', '/', data, _); alert('Done!'); 57 https://github.com/Sage/streamlinejs
  • 58.
    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
  • 59.
    Streamlinejs •  Генерация кода– результат ужасен! •  Шум из массы _ •  Его цель – выполнять асинхронный код последовательно 59
  • 60.
    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
  • 61.
    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
  • 62.
    Асинхронность •  Событийный ввод-вывод • Работа с GUI •  Паттерны –  Callback –  EventEmitter –  Promise –  Deferred •  Хаки –  Streamline –  Fibers •  Библиотеки –  Step –  Q 62
  • 63.