Async & Await
James Hunter
@cccc00
Warning To Functional People
So many side effects
::console.log
console.log.bind(console)
Promise.resolve(4)
.then(::console.log)
// 4Works Like
=
Some friends...
function bob (x) {
return x + x
}
function bob (x) {
return x + x
}
bob is reliable
function bob (x) {
return x + x
}
bob is predictable
function bob (x) {
return x + x
}
bob always answers arguments the same way
function bob (x) {
return x + x
}
bob is a singular synchronous operation
function steve (x) {
const y = inc()
return x + y
}
function steve (x) {
const y = inc()
return x + y
}
steve is nice
function steve (x) {
const y = inc()
return x + y
}
steve has a second job on the side
function steve (x) {
const y = inc()
return x + y
}
steves second job blocks him from
doing his actual job
function steve (x) {
const y = inc()
return x + y
}
steve is a singular synchronous operation
function cam (x, cb) {
inc((err, y) => {
cb(err, x + y)
})
}
cam.
function cam (x, cb) {
inc((err, y) => {
cb(err, x + y)
})
}
cam...
function cam (x, cb) {
inc((err, y) => {
cb(err, x + y)
})
}
cam replies right away
function cam (x, cb) {
inc((err, y) => {
cb(err, x + y)
})
}
cam is all over the place
function cam (x, cb) {
inc((err, y) => {
cb(err, x + y)
})
}
cam likes rules, not tools
function cam (x, cb) {
inc((err, y) => {
cb(err, x + y)
})
}
cam is a singular asynchronous operation
function cam (x, cb) {
inc((err, y) => {
cb(err, x + y)
})
}
function pat (x) {
return inc()
.then(y => x + y)
.catch(::console.error)
}
function pat (x) {
return inc()
.then(y => x + y)
.catch(::console.error)
}
pat (like cam) replies right away
function pat (x) {
return inc()
.then(y => x + y)
.catch(::console.error)
}
pat looks simple
function pat (x) {
return inc()
.then(y => x + y)
.catch(::console.error)
}
pat thinks differently than you
function pat (x) {
return inc()
.then(y => x + y)
.catch(::console.error)
}
pat is a singular asynchronous operation
I know what you are thinking
I know what you are thinking
Functions aren't people
get off the stage
I know what you are thinking
Functions aren't people
But in all seriousness
Why does this stuff
have to be so complicated
much synchronous
very asynchronous
such promises
many callbacks

Why cant I just write it
like a normal function
such synchronous
much asynchronous
many promises
very callbacks

Like steve...
very synchronous
many asynchronous
much promises
such callbacks

function steve (x) {
const y = inc()
return x + y
}
good ol' steve
function steve (x) {
const y = inc()
return x + y
}
I want to write my asynchronous code like this
function steve (x) {
const y = inc()
return x + y
}
I want a super steve
function steve (x) {
const y = inc()
return x + y
}
I want a super steve

– Marvel
How close can we get to a
singular asynchronous
version of steve?
function steve (x) {
const y = inc()
return x + y
}
import { coroutine } from "bluebird"
let superSteve = coroutine(function * (x) {
const y = yield inc()
return x + y
})Turns out pretty close
function steve (x) {
const y = inc()
return x + y
}
import { coroutine } from "bluebird"
let superSteve = coroutine(function * (x) {
const y = yield inc()
return x + y
})Turns out pretty close
let steve = function (x) {
const y = inc()
return x + y
}
What is this black magic
how is it doing this
import { coroutine } from "bluebird"
let superSteve = coroutine(function * (x) {
const y = yield inc()
return x + y
})well....

3 things main points
1 – Iterators
1 – Iterators
are synchronous sequences, where the consumer pulls data at the rate they desire
– Domenic Denicola
let iter = ["a","b","c"].entries()
iter.next() // {value: [0,"a"], done: false}
iter.next() // {value: [1,"b"], done: false}
iter.next() // {value: [2,"c"], done: false}
iter.next() // {done: true}
iter.next() // {done: true}2 – Generators
2 – Generators
"Basic" use of generator functions is to simply yield values and create a sequence, sending values out of the generator function (through the iterable) at the rate the consumer desires.
– Domenic Denicola
function * bananas () {
while (1) {
yield "banana"
}
}
function take (n, iter) {
let result = []
while (result.length < n) {
result.push(iter.next().value)
}
return result
}
take(2, bananas())
// ["banana", "banana"]3 - Generators (again)
3 - Generators (again)
Generators also have an "advanced" mode, where you can send values into the generator function
– Domenic Denicola
function double (genFn) {
let iter = genFn()
let value = 0
let done = false
while (!done) {
const next = iter.next(value * 2)
done = next.done
value = next.value
}
return value
}
double(function * () {
const a = yield 1
const b = yield 2
return a + b
}) // 6
import { coroutine } from "bluebird"
let superSteve = coroutine(function * (x) {
const y = yield inc()
return x + y
})coroutine (spawn) is a function that
inverts the normal consumer-producer
model of the generator to create iterable sequences
The Hack Is...
import { coroutine } from "bluebird"
let superSteve = coroutine(function * (x) {
const y = yield inc()
return x + y
})
function steve (x) {
const y = inc()
return x + y
}
But... Can we get even closer to steve?
async function superSteve (x) {
const y = await inc()
return x + y
}
function steve (x) {
const y = inc()
return x + y
}
async function superSteve (x) {
const y = await inc()
return x + y
}
function steve (x) {
const y = inc()
return x + y
}
async function superSteve (x) {
const y = await inc()
return x + y
}
-
usable today with transpilers like babel (stage 1)
async function superSteve (x) {
const y = await inc()
return x + y
}
-
usable today with transpilers like babel (stage 1)
-
declaratively say that we are going to wait on inc
async function superSteve (x) {
const y = await inc()
return x + y
}
-
usable today with transpilers like babel (stage 1)
-
declaratively say that we are going to wait on inc
-
the generator stuff is an implementation detail
async function superSteve (x) {
const y = await inc()
return x + y
}
-
usable today with transpilers like babel (stage 1)
-
declaratively say that we are going to wait on inc
-
the generator stuff is an implementation detail
- returns a promise
async function superSteve (x) {
const y = await inc()
return x + y
}
async steveception (x) {
const a = await superSteve(x)
const b = await superSteve(a)
const c = await superSteve(b)
return a + b + c
}
-
usable today with transpilers like babel (stage 1)
-
declaratively say that we are going to wait on inc
-
the generator stuff is an implementation detail
- returns a promise
async function superSteve (x) {
const y = await inc()
return x + y
}
async steveception (x) {
try {
const a = await superSteve(x)
const b = await superSteve(a)
const c = await superSteve(b)
} catch (err) {
console.error(err)
let a = b = c = 1
} finally {
return a + b + c
}
}
-
usable today with transpilers like babel (stage 1)
-
declaratively say that we are going to wait on inc
-
the generator stuff is an implementation detail
- returns a promise
- try/catch/finally
async function superSteve (x) {
const y = await inc()
return x + y
}
function pat (x) {
return inc()
.then(y => x + y)
.catch(::console.error)
}
function cam (x, cb) {
inc((err, y) => {
cb(err, x + y)
})
}
async function superSteve (x) {
const y = await inc()
return x + y
}
function steve (x) {
const y = inc()
return x + y
}
- async function proposal
- how to enable babel stage 1
- my twitter: @cccc00
- these slides: bit.ly/jh-async
The Illustrations
– by –

@mrdougal
Async & Await
– by –
@cccc00 – James Hunter
Async & Await #wdcode
By James Hunter
Async & Await #wdcode
- 2,327