Async Functions
Awaiting You
Tomasz Ducin
Tomasz Ducin
19th June 2017, Warsaw

async
functions
await
ing you
Tomasz Ducin
25th May 2017, Warsaw
Async Functions
Awaiting You
Tomasz Ducin
JavaScript, Java, Python
software dev @ Ivanti
trainer @ Bottega IT Minds




functions
sync vs async
promises
async await
coroutines
CSP
generators
callbacks
events
reactive streams
run to completion
event loop
a Promise of
a single operation
to be completed in future
fetchData()
.then(callbackFn)
.catch(errorHandlerFn)
myCustomOperation()
.then(callbackFn)
.catch(errorHandlerFn)
Promise - states
pending
fulfilled
rejected
initial state,
not settled yet
operation has failed
operation has completed successfully
settled
promise limitations
-
single item
-
one-time item
-
greedy
-
not cancellable
-
values unavailable outside the chain
-
only previous step value available
return asyncOp1();
function promiseChain(){
return asyncOp1()
.then(asyncOp2)
.then(asyncOp3)
.then(asyncOp4);
}
return asyncOp1()
.then(asyncOp2);
return asyncOp1()
.then(asyncOp2)
.then(asyncOp3);
return asyncOp1()
.then(asyncOp2)
.then(asyncOp3)
.then(asyncOp4);
function sequential(){
return asyncOp1()
.then(asyncOp2)
.then(asyncOp3)
.then(asyncOp4);
}
Sequential Processing
op1
op2
op3
op4
sequential()
.then(anotherAsync)
another
function parallel(){
var p1 = asyncOp1();
var p2 = asyncOp2();
var p3 = asyncOp3();
var p4 = asyncOp4();
return Promise.all(
[p1, p2, p3, p4]);
}
Concurrent Processing
op1
another
.all
parallel()
.then(anotherAsync)
op2
op3
op4
Promise.all([p1, p2, p3, p4])
.then( ([v1, v2, v3, v4]) => {...})
.catch( reason => {...})
Promise Aggregates
Promise.race([p1, p2, p3, p4])
.then( value => {...})
.catch( reason => {...})
Promise.any([p1, p2, p3, p4])
.then( value => {...})
.catch( ([r1, r2, r3, r4]) => {...})



all
race
any
Promise.some([p1, p2, p3, p4], 2)
.then( (v1, v2) => {...})
.catch( ([r1, r2, r3]) => {...})

some
didn't mention
-
chaining, splitting, joining
-
error handling
-
antipatterns
(broken chain, deferred) -
jQuery 1.x, 2.x promise broken
-
referring to previous steps

function zeroOneTwo(){
return [0, 1, 2];
}
function* zeroOneTwo(){
yield 0;
yield 1;
yield 2;
}
lazy
greedy
list
generator
synchronous
synchronous
for (var i of zeroOneTwo()) {
console.log(i);
} // 1 2 3
function* generator(){
console.log(1, "inside");
yield "A";
console.log(2, "inside");
yield "B";
}
var iterator = generator();
console.log(1, "outside");
iterator.next();
console.log(2, "outside");
iterator.next();
console.log(3, "outside");
synchronous
Generators
vs run to completion
1: outside
1: inside
2: outside
2: inside
3: outside
function* generate(){
console.log(1, "inside");
let recv = yield "A";
console.log(2, "inside", recv);
yield "B";
}
var iter = generate();
console.log(1, "outside");
let item = iter.next();
console.log(2, "outside", item.value);
iter.next('hey!');
console.log(3, "outside");
synchronous
Generators
vs run to completion
1: outside
1: inside
2: outside, A
2: inside, hey!
3: outside
= coroutines
promises + generators
+ 1 tiny wrapper
- start immediately
-
suspend on promise
- resume when settled
- promise pending...
- resolve/ reject calls next
writing asynchronous code in synchronous manner
function* sequential(){
var v1 = yield asyncOp1();
var v2 = yield asyncOp2(v1);
var v3 = yield asyncOp3(v2);
return asyncOp4(v3);
}
let asyncSequential
= async(sequential);
Sequential Processing
asyncSequential()
.then(anotherAsync)
op1
op2
op3
op4
another
function* parallel(){
var p1 = asyncOp1();
var p2 = asyncOp2();
var p3 = asyncOp3();
var p4 = asyncOp4();
return yield p1 + yield p2
+ yield p3 + yield p4;
}
let asyncParallel
= async(parallel)
asyncParallel()
.then(anotherAsync)
op1
another
all yield
op2
op3
op4
Concurrent Processing
function async(makeGenerator){
return function () {
var generator = makeGenerator.apply(this, arguments);
function handle(result){
// result => { done: [Boolean], value: [Object] }
if (result.done) return Promise.resolve(result.value);
return Promise.resolve(result.value).then(function (res){
return handle(generator.next(res));
}, function (err){
return handle(generator.throw(err));
});
}
try {
return handle(generator.next());
} catch (ex) {
return Promise.reject(ex);
}
}
}
a couple of lines that
do the right thing...

ES2017 / ES8
async function sequential(){
var v1 = await asyncOp1();
var v2 = await asyncOp2(v1);
var v3 = await asyncOp3(v2);
return asyncOp4(v3);
}
Sequential Processing
sequential()
.then(anotherAsync)
op1
op2
op3
op4
another
async function parallel(){
var p1 = asyncOp1();
var p2 = asyncOp2();
var p3 = asyncOp3();
var p4 = asyncOp4();
return await p1 + await p2
+ await p3 + await p4;
}
parallel()
.then(anotherAsync)
op1
another
all await
op2
op3
op4
Concurrent Processing
Pipeline scope
function promiseChain(){
return asyncOp1()
.then(asyncOp2)
.then(asyncOp3)
.then(asyncOp4 ???);
}
using data from previous steps
async function sequential(){
var v1 = await asyncOp1();
var v2 = await asyncOp2(v1);
var v3 = await asyncOp3(v2);
return asyncOp4(v1, v2, v3);
}
No nested functions
same as in generators
async function renderChapters(urls) {
urls.map(getJSON)
.forEach(p => addToPage((await p).html));
}
async function renderChapters(urls) {
urls.map(getJSON)
.forEach(async p => addToPage((await p).html));
}
Syntax Error
parallel
Async Arrow Functions
(async x => x ** 2);
(async x => { return x ** 2; });
(async (x, y) => x ** y);
(async (x, y) => { return x ** y; });
instead of Promise.resolve
const square = (async x => x ** 2);
square(5) // same as Promise.resolve(25)
square(5).then(console.log)
// output: 25
Async Iteration
for await (const line of readLines(filePath)) {
console.log(line);
}
syncIterator.next()
// -> { value: ..., done: ... }
asyncIterator.next()
// -> Promise resolving with
// { value: ..., done: ... }
.then(({ value, done }) => /* ... */);
lazy and asynchronous
Top-level await
// all awaited functions return a promise
// all awaited functions return a promise
await delay(2000);
// all awaited functions return a promise
await delay(2000);
// webservices
const flowers = await fetch('flowers.jpg');
// all awaited functions return a promise
await delay(2000);
// webservices
const flowers = await fetch('flowers.jpg');
// I/O operations
let content = '...';
let fileName = 'filename.json';
await writeFile(fileName, content);
await doSomeProcessing(fileName);
Rich Harris, creator of Rollup
var data = await something();
// import gets blocked
const m = import 'module';
m.run();
if (!Array.prototype.myMethod){
...
await something();
}
var data = await something();
export default data;
module.js
Top-level await
consumer.js
THX!
