Upload
moscowjs
View
194
Download
1
Tags:
Embed Size (px)
Citation preview
How to stop debugging asynchronous code
and start living
Andrey Salomatin BerlinJS
18.06.2015
Schlecht!Script
Schlecht!Script
function f1*red(a, b) {…}
f1*red(a, b)
function f2*blue(c) {…}
f2*blue(c)
3
Functions have colors
Schlecht!Script
/* OK! */
function outer*blue() {
inner*blue()
}
4
Blue functions can only call other blue functions
/* NOT OK! */
function outer*blue() {
inner*red()
}
Schlecht!Script
/* OK! */
function outer*red() {
inner2*red()
}
5
Red functions can call red and blue functions
/* OK! */
function outer*red() {
inner2*blue()
}
Implementing and calling red functions is painful!
6
Schlecht!Script7
Red functions can only be named in german!
/* Can’t be interpreted */
function authUser*red() {…}
function getName*red() {…}
Schlecht!Script8
Red functions can only be named in german!
/* RICHTIG! */
function benutzerAutorisierung!*rot() {…}
function nameErhalten!*rot() {…}
How to write in Schlecht!Script?
9
JavaScript
JavaScript extends
Schlecht!Script
11
Dealing with asynchronous functions
is a nightmare
12
JavaScript
• if/else, for, return don’t work
• No try/catch • Abstraction is broken
13
Dealing with asynchronous functions is painful
// execute in sequence
for (var i = 0; i < 10; i++) {
if (shouldProcess(i)) {
results.push(process(i));
}
}
14
JavaScript
if/for synchronously
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 asynchronously
JavaScript
• if/else, for, return don’t work
• No try/catch • Abstraction is broken
16
Dealing with asynchronous functions is painful
Asynchronous codein JavaScript
17
Андрей Саломатин
Productive Mobile MoscowJS RadioJS
18
@filipovskii
Asynchronous
Multiple events
Single operation
20
Asynchronous: two cases
Control
22
Exceptions
23
Unified interface
24
• Handling multiple asynchronous eventsEventEmitterStream
• Handling single asynchronous operation Continuation Passing Style PromisesCoroutines
26
ES6
• Handling multiple asynchronous eventsAsync Generators
• Handling single asynchronous operation Async/Await
27
ES7
ES6
Handling multiple asynchronous events
29
30
Handling multiple asynchronous events
EventEmitter
Stream
EventEmitter31
Object that emits events
EventEmitter32
Examples
Browser: XMLHttpRequest
Node: http.Server
EventEmitter
emitter.addEventListener(eventName, cb);
emitter.removeEventListener(eventName, cb);
33
API
EventEmitter34
XMLHttpRequest
progress (n) load (1) abort (1) error (1)
EventEmitter35
Implementations
Browser + Node:EventEmitter3, Tiny Emitter
Node:Node EventEmitter
36
Handling multiple asynchronous events
EventEmitter
Stream
37
EventEmitter
Stream
Handling multiple asynchronous events
Stream of data
Stream38
Stream39
Examples
Node: fs.createReadStream(path)
Node: gulp.src(pattern)
Stream40
Types of streams
stylus files css files css prefixed files
gulp.src('*.styl') stylus() autoprefixer() gulp.dest('dist')
Stream41
source transform transform consumer
gulp.src('*.styl') stylus() autoprefixer() gulp.dest('dist')
Types of streams
42
Stream43
Implementations
Isomorphic:RxJS, Kefir, Bacon.js
Node:Node Streams
44
EventEmitter Stream
Handling multiple asynchronous events
45
Control
Excpetions
Unified Interface
EventEmitter, Stream
Asynchronous operations
46
47
Asynchronous operations
Continuation Passing Style Promises
Coroutines
Continuation Passing Style48
Examples
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);
}
49
Continuation Passing Style
Get twitter feed synchronously
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);
});
});
});
50
Continuation Passing Style
Get twitter feed asynchronously
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); }
51
Continuation Passing Style
Get twitter feed asynchronously
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); }
52
Continuation Passing Style
Holen Sie sich die Band tweets asynchron!
53Schlecht!Script
54
Asynchronous operations
Continuation Passing Style
Promises
Coroutines
55
Continuation Passing Style
Promises
Coroutines
Asynchronous operations
Object represents asynchronous operation
Promises56
Promise.prototype.then(successCb, errorCb);
57
API
Promises
fetchUser(userId)
.then(fetchFollowingUsers)
.then(fetchTweets)
.then(handleResult, handleError);
58
Promises
API
Promises vs
Continuation Passing Style
59
60
Implementations
jQuery.Deffered Bluebird RSVP Q
Promises
61
Continuation Passing Style
Promises
Coroutines
Asynchronous operations
62
Continuation Passing Style
Promises
Coroutines
Asynchronous operations
Coroutines63
Coroutines
function getUserName(userId) {
var user = getUser(userId);
return user.name;
}
64
Stop the Earth!
Function can be paused and resumed later
65
Coroutines
function * getUserName (userId) {
var user = yield getUser(userId);
return user.name;
};
66
Generators: step 1 of 3
Coroutines
function * getUserName (userId) {
var user = yield getUser(userId);
return user.name;
};
67
Coroutines
Generators: step 1 of 3
getUserName = co.wrap(function * (userId) {
var user = yield getUser(userId);
return user.name;
});
68
Coroutines
Generators: step 2 of 3
getUserName = co.wrap(function * (userId) {
var user = yield getUser(userId);
return user.name;
});
69
Coroutines
Generators: step 2 of 3
userNamePromise = getUserName(userId);
70
Coroutines
Generators: step 3 of 3
Using generators for asynchronous code —
is a hack
71
Using generators for asynchronous code —
is a hack
72
(but I will not tell anyone)
73
Implementations
Browser + Node:co (generators), task.js (generators)
Node:Fibers
Coroutines
74
Continuation Passing Style
Promises
Coroutines
Asynchronous operations
75
Control
Exceptions
Unified Interface
CPS, Promises, Coroutines
76
ES6
• Handling multiple asynchronous eventsEventEmitterStream
• Handling single asynchronous operation Continuation Passing Style PromisesCoroutines
ES7
79
ES7
• Handling single asynchronous operation Async/Await
• Handling multiple asynchronous eventsAsync Generators
80
ES7ES7
• Handling single asynchronous operation Async/Await
• Handling multiple asynchronous eventsAsync Generators
Async/Await
getUserName = co.wrap(function * (userId) {
var user = yield getUser(userId);
return user.name;
});
81
Generators
async function getUserName(userId) {
var user = await getUser(userId);
return user.name;
}
82
Async/Await
Async/Await
async function getUserName(userId) {
var user = await getUser(userId);
return user.name;
}
83
Async функция
Async/Await
Asynchronous functions legalized in ES7
84
Async/Await
85
ES7
• Handling single asynchronous operation Async/Await
• Handling multiple asynchronous eventsAsync Generators
86
ES7
• Handling single asynchronous operation Async/Await
• Handling multiple asynchronous eventsAsync Generators
Event subscription for human beings
Async Generators87
async function doDraw() {
for (let ev on observe(win, 'mousemove')) {
draw(ev.clientX, ev.clientY);
}
}
88
DOM Events
Async Generators
async function doDraw() {
for (let ev on observe(win, 'mousemove')) {
draw(ev.clientX, ev.clientY);
}
}
89
Async Generators
DOM Events
doDrawPromise = doDraw();
90
Async Generators
DOM Events
async function *filterWSMessages(ws) {
for (let msg on observe(ws, 'message')) {
if (isValid(msg)) yield msg;
}
}
91
WebSocket messages
Async Generators
async function *filterWSMessages(ws) {
for (let msg on observe(ws, 'message')) {
if (isValid(msg)) yield msg;
}
}
92
WebSocket messages
Async Generators
??? = filterWSMessages(ws);
??? = observe(win, 'mousemove');
??? = observe(ws, 'message');
93
What does Async Generator return?
Async Generators
messagesObservable = filterWSMessages(ws);
eventsObservable = observe(win, 'mousemove');
eventsObservable = observe(ws, 'message');
94
Async Generators
What does Async Generator return?
Observables
Streamsaka
96
ES7
• Handling single asynchronous operation Async/Await
• Handling multiple asynchronous eventsAsync Generators
ES6 and ES7: asynchronous operations
97
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);
});
});
});
98
ES6 and ES7
Get twitter feed: CPS
fetchUser(userId)
.then(fetchFollowingUsers)
.then(fetchTweets)
.then(handleResult, handleError);
99
Get twitter feed: Promise
ES6 and ES7
try {
var user = await fetchUser(userId);
var following = await fetchFollowingUsers(userId);
var tweets = await fetchTweets(following);
handleResult(tweets);
} catch (err) {
handleError(err);
}
100
Get twitter feed: Async/Await
ES6 and ES7
ES6 and ES7: handling multiple events
101
var handler = function(ev) {
if (canDraw(ev)) {
draw(ev.clientX, ev.clientY);
}
};
window.addEventListener('mousemove', handler);
window.removeEventListener('mousemove', handler); // later
102
DOM events: EventEmitter
ES6 and ES7
Kefir.fromEvent(window, 'mousemove')
.filter(canDraw)
.onValue(function(ev) {
draw(ev.clientX, ev.clientY)
})
.end(); // later
103
DOM events: Stream
ES6 and ES7
for (ev on observe(window, 'mousemove')) {
if (canDraw(ev)) {
draw(ev.clientX, ev.clientY);
}
}
104
DOM events: Async Generators
ES6 and ES7
How to stop debugging asynchronous code
and start living
105
Define the case
106
Consider restrictions
107
Use best practices
108
Schlecht!Script?
Thank you!
Andrey Salomatin @filipovskii
BerlinJS 18.06.2015