View
1.011
Download
0
Category
Preview:
Citation preview
Как перестать отлаживать асинхронный код и начать жить
Андрей Саломатин FrontendConf, Москва
21.05.2015
Schlecht!Script
Schlecht!Script
function f1*red(a, b) {…}
f1*red(a, b)
function f2*blue(c) {…}
f2*blue(c)
3
Функции имеют цвет
Schlecht!Script
/* OK! */
function outer*blue() {
inner*blue()
}
4
Синие могут вызывать только другие синие функции
/* NOT OK! */
function outer*blue() {
inner*red()
}
Schlecht!Script
/* OK! */
function outer*red() {
inner2*red()
}
5
Красные могут вызывать и красные и синие функции
/* OK! */
function outer*red() {
inner2*blue()
}
Писать и вызывать красные функции больно!
6
Schlecht!Script7
Красные функции нужно называть на немецком!
/* Интерпретатор не поймёт */
function authUser*red() {…}
function getName*red() {…}
Schlecht!Script8
Красные функции нужно называть на немецком!
/* RICHTIG! */
function benutzerAutorisierung!*rot() {…}
function nameErhalten!*rot() {…}
Как писать на Schlecht!Script?
9
JavaScript
JavaScript extends
Schlecht!Script
11
Асинхронные функции это боль
12
JavaScript
• По-другому работают if/else, for, return • Нет try/catch • Ломают абстракцию
13
Асинхронные функции это боль
// выполнять последовательно
for (var i = 0; i < 10; i++) {
if (shouldProcess(i)) {
results.push(process(i));
}
}
14
JavaScript
if/for синхронно
function maybeProcess(i) {
if (i >= 10) { return; }
shouldProcess(function(should) {
if (should) {
process(i, function(result) {
results.push(result);
maybeProcess(i++);
});
}
maybeProcess(i++);
});
}
maybeProcess(0);
15
JavaScript
if/for асинхронно
JavaScript
• Не работают if/then, for и т.д. • Нет try/catch • Ломают абстракцию
16
Асинхронные функции это боль
Асинхронностьв JavaScript
17
Андрей Саломатин
Productive Mobile MoscowJS RadioJS
18
@filipovskii
Асинхронность
Множество событий
Единичная операция
20
Асинхронность: два сценария
Контроль
22
Исключения
23
Единый интерфейс
24
25
КонтрольИсключения
Единый интерфейс
• Работа с множеством событийEventEmitterStream
• Работа с асинхронными операциямиContinuation Passing Style PromisesCoroutines
27
ES6
• Работа с множеством событийAsync Generators
• Работа с асинхронными операциямиAsync/Await
28
ES7
ES6
Работа с множеством асинхронных
событий
30
31
Работа с множеством асинхронных событий
EventEmitter
Stream
EventEmitter32
Объект — источник событий
EventEmitter33
Примеры
Browser: XMLHttpRequest
Node: http.Server
EventEmitter
emitter.addEventListener(eventName, cb);
emitter.removeEventListener(eventName, cb);
34
API
EventEmitter35
События XMLHttpRequest
progress (n) load (1) abort (1) error (1)
EventEmitter36
Реализации
Браузер + Node:EventEmitter3, Tiny Emitter
Node:Node EventEmitter
37
Работа с множеством асинхронных событий
EventEmitter
Stream
38
EventEmitter
Stream
Работа с множеством асинхронных событий
Поток данных
Stream39
Stream40
Примеры
Node: fs.createReadStream(path)
Node: gulp.src(pattern)
Stream41
Типы потоков
stylus files css files css prefixed files
gulp.src('*.styl') stylus() autoprefixer() gulp.dest('dist')
Stream42
источник преобразование преобразование потребитель
gulp.src('*.styl') stylus() autoprefixer() gulp.dest('dist')
Типы потоков
43
Stream44
Реализации
Изоморфные: RxJS, Kefir, Bacon.js
Node:Node Streams
45
Работа с множеством асинхронных событий
EventEmitter Stream
46
Контроль
Исключения
Единый интерфейс
EventEmitter, Stream
Работа с асинхронными операциями
47
48
Работа с асинхронными операциями
Continuation Passing Style Promises
Coroutines
Continuation Passing Style49
Примеры
Browser:
navigator.geolocation.getCurrentPosition(cb)
Node:
fs.stat(path, cb)
try {
var user = fetchUser(userId);
var following = fetchFollowingUsers(userId);
var tweets = fetchTweets(following);
handleResult(tweets);
} catch (err) {
handleError(err);
}
50
Continuation Passing Style
Получить ленту твитов синхронно Получить ленту твитов асинхронно
fetchUser(userId, function(err, user) {
if (err) { return handleError(err); }
fetchFollowingUsers(user, function(err, following) {
if (err) { return handleError(err); }
fetchTweets(following, function(err, tweets) {
if (err) { return handleError(err); }
handleResult(tweets);
});
});
});
51
Continuation Passing Style
Получить ленту твитов асинхронно
fetchUser(userId, function(err, user) {
if (err) { return handleError(err); }
fetchFollowingUsers(user, function(err, following) {
if (err) { return handleError(err); }
fetchTweets(following, function(err, tweets) {
if (err) { return handleError(err); }
52
Continuation Passing Style
Получить ленту твитов асинхронно
holenBenutzer!*rot(userId, function(err, user) {
if (err) { return handleError*blue(err); }
holenFolgendenBenutzer!*rot(user, function(err, following) {
if (err) { return handleError*blue(err); }
holenTweets!*rot(following, function(err, tweets) {
if (err) { return handleError(err); }
53
Continuation Passing Style
Holen Sie sich die Band tweets asynchron!
54Schlecht!Script
55
Работа с асинхронными операциями
Continuation Passing Style
Promises
Coroutines
56
Continuation Passing Style
Promises
Coroutines
Работа с асинхронными операциями
Объект — асинхронная операция
Promises57
Promise.prototype.then(successCb, errorCb);
58
API
Promises
fetchUser(userId)
.then(fetchFollowingUsers)
.then(fetchTweets)
.then(handleResult, handleError);
59
Promises
API
Promises vs
Continuation Passing Style
60
61
Реализации
jQuery.Deffered Bluebird RSVP Q
Promises
62
Continuation Passing Style
Promises
Coroutines
Работа с асинхронными операциями
63
Continuation Passing Style
Promises
Coroutines
Работа с асинхронными операциями
Coroutines64
Coroutines
function getUserName(userId) {
var user = getUser(userId);
return user.name;
}
65
Остановите землю!
Функция, которую можно приостановить и возобновить
позже
66
Coroutines
function * getUserName (userId) {
var user = yield getUser(userId);
return user.name;
};
67
Генераторы: шаг 1 из 3
Coroutines
function * getUserName (userId) {
var user = yield getUser(userId);
return user.name;
};
68
Coroutines
Генераторы: шаг 1 из 3
getUserName = co.wrap(function * (userId) {
var user = yield getUser(userId);
return user.name;
});
69
Coroutines
Генераторы: шаг 2 из 3
getUserName = co.wrap(function * (userId) {
var user = yield getUser(userId);
return user.name;
});
70
Coroutines
Генераторы: шаг 2 из 3
userNamePromise = getUserName(userId);
71
Coroutines
Генераторы: шаг 3 из 3
Использовать генераторы для асинхронного кода —
это хак
72
Использовать генераторы для асинхронного кода —
это хак
73
(но я вас не выдам)
74
Реализации
Браузер + Node (используют транспайлер):co (generators), task.js (generators)
Node (использует транспайлер):Fibers
Coroutines
75
Continuation Passing Style
Promises
Coroutines
Работа с асинхронными операциями
76
Контроль
Исключения
Единый интерфейс
CPS, Promises, Coroutines
Работа с множеством событий: EventEmitter Stream
Работа с асинхронными операциями: CPS Promise Coroutine
77
ES6
ES7
Работа с асинхронными операциями: Async/Await
Работа с множеством событий: Async Generators
80
ES7
Работа с асинхронными операциями: Async/Await
Работа с множеством событий: Async Generators
81
ES7ES7
Async/Await
getUserName = co.wrap(function * (userId) {
var user = yield getUser(userId);
return user.name;
});
82
Генераторы
async function getUserName(userId) {
var user = await getUser(userId);
return user.name;
}
83
Async/Await
Async/Await
async function getUserName(userId) {
var user = await getUser(userId);
return user.name;
}
84
Асинхронная функция
Async/Await
Асинхронные функции легализованы в ES7
85
Async/Await
Работа с асинхронными операциями: Async/Await
Работа с множеством событий: Async Generators
86
ES7
Работа с асинхронными операциями: Async/Await
Работа с множеством событий: Async Generators
87
ES7
Подписка на события для людей
Async Generators88
async function doDraw() {
for (let ev on observe(win, 'mousemove')) {
draw(ev.clientX, ev.clientY);
}
}
89
События DOM
Async Generators
async function doDraw() {
for (let ev on observe(win, 'mousemove')) {
draw(ev.clientX, ev.clientY);
}
}
90
Async Generators
События DOM
doDrawPromise = doDraw();
91
Async Generators
События DOM
async function *filterWSMessages(ws) {
for (let msg on observe(ws, 'message')) {
if (isValid(msg)) yield msg;
}
}
92
WebSocket сообщения
Async Generators
async function *filterWSMessages(ws) {
for (let msg on observe(ws, 'message')) {
if (isValid(msg)) yield msg;
}
}
93
WebSocket сообщения
Async Generators
??? = filterWSMessages(ws);
??? = observe(win, 'mousemove');
??? = observe(ws, 'message');
94
Что возвращает Async Generator?
Async Generators
messagesObservable = filterWSMessages(ws);
eventsObservable = observe(win, 'mousemove');
eventsObservable = observe(ws, 'message');
95
Async Generators
Что возвращает Async Generator?
Observables
Streamsaka
Работа с асинхронными операциями: Async/Await
Работа с множеством событий: Async Generators
97
ES7
ES6 и ES7: асинхронные операции
98
fetchUser(userId, function(err, user) {
if (err) { return handleError(err); }
fetchFollowingUsers(user, function(err, following) {
if (err) { return handleError(err); }
fetchTweets(following, function(err, tweets) {
if (err) { return handleError(err); }
handleResult(tweets);
});
});
});
99
ES6 и ES7
Получить ленту твитов: CPS
fetchUser(userId)
.then(fetchFollowingUsers)
.then(fetchTweets)
.then(handleResult, handleError);
100
Получить ленту твитов: Promise
ES6 и ES7
try {
var user = await fetchUser(userId);
var following = await fetchFollowingUsers(userId);
var tweets = await fetchTweets(following);
handleResult(tweets);
} catch (err) {
handleError(err);
}
101
Получить ленту твитов: Async/Await
ES6 и ES7
ES6 и ES7: обработка множества событий
102
var handler = function(ev) {
if (canDraw(ev)) {
draw(ev.clientX, ev.clientY);
}
};
window.addEventListener('mousemove', handler);
window.removeEventListener('mousemove', handler); // позже
103
DOM события: EventEmitter
ES6 и ES7
Kefir.fromEvent(window, 'mousemove')
.filter(canDraw)
.onValue(function(ev) {
draw(ev.clientX, ev.clientY)
})
.end(); // позже
104
DOM события: Stream
ES6 и ES7
for (ev on observe(window, 'mousemove')) {
if (canDraw(ev)) {
draw(ev.clientX, ev.clientY);
}
}
105
DOM события: Async Generators
ES6 и ES7
Как перестать отлаживать асинхронный
код и начать жить
106
Определите задачу
107
Обдумайте ограничения
108
Используйте лучшие практики
109
Schlecht!Script?
Спасибо!
bit.ly/async-js
Андрей Саломатин @filipovskii
FrontendConf, Москва 21.05.2015
Recommended