Skip to content

Instantly share code, notes, and snippets.

@CrabDude
Created November 4, 2015 02:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save CrabDude/75981463cfd3d7605b2f to your computer and use it in GitHub Desktop.
Save CrabDude/75981463cfd3d7605b2f to your computer and use it in GitHub Desktop.
BayNode Node Night 11/3/15: async/await by Adam Crabtree
<!DOCTYPE html>
<html>
<head>
<title>Async Await</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
@import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
body { font-family: 'Droid Serif'; }
h1, h2, h3 {
font-family: 'Yanone Kaffeesatz';
font-weight: normal;
}
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
</style>
</head>
<body>
<textarea id="source">
class: center, middle
# Async/Await
Simpler asynchronous JavaScript programming.
---
# Overview
**3 mechanisms of asynchronous programming:**
1. Callbacks
```javascript
fs.readFile(__filename, (err data) => { /* ... */ })
```
1. Promises
```javascript
// Using pn
fs.readFile(__filename)
.then(data => { /* ... */ })
.catch(err => { /* ... */ })
```
1. Async/Await
```javascript
// Within a function marked `async`
let data = fs.readFile(__filename)
```
---
# Why not callbacks?
---
# Why not callbacks?
**Simplest in concept, manual and erorr-prone in practice.**
---
# Why not callbacks?
**Simplest in concept, manual and erorr-prone in practice.**
```javascript
fs.stat(dirPath, (err, stats) => {
})
.
```
---
# Why not callbacks?
**Simplest in concept, manual and erorr-prone in practice.**
```javascript
fs.stat(dirPath, (err, stats) => {
let notString = stats.isDirectory() ? "" : " not"
console.log(dirPath + ' is ' + notString + ' a directory.')
})
.
```
---
# Why not callbacks?
**Simplest in concept, manual and erorr-prone in practice.**
```javascript
fs.stat(dirPath, (err, stats) => {
// Remember to handle err
if (err) console.log(dirPath + ' is not a directory.')
let notString = stats.isDirectory() ? "" : " not"
console.log(dirPath + ' is ' + notString + ' a directory.')
})
.
```
---
# Why not callbacks?
**Simplest in concept, manual and erorr-prone in practice.**
```javascript
fs.stat(dirPath, (err, stats) => {
// Remember to handle err & early return
if (err) return console.log(dirPath + ' is not a directory.')
let notString = stats.isDirectory() ? "" : " not"
console.log(dirPath + ' is ' + notString + ' a directory.')
})
.
```
---
# Why not callbacks?
**Simplest in concept, manual and erorr-prone in practice.**
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
// Remember to handle err & early return
if (err) return callback(null, false)
let notString = stats.isDirectory() ? "" : " not"
console.log(dirPath + ' is ' + notString + ' a directory.')
})
}
```
---
# Why not callbacks?
**Simplest in concept, manual and erorr-prone in practice.**
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
// Remember to handle err and early return
if (err) return callback(null, false)
// Remember to call callback
callback(null, stats.isDirectory())
})
}
```
---
# Why not callbacks?
**Simplest in concept, manual and erorr-prone in practice.**
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
// Remember to handle err and early return
if (err) return callback(null, false)
// Remember to call callback
callback(null, stats.isDirectory())
})
}
```
**Rinse & Repeat:**
```javascript
isDir(dirPath, (err, isDir) => {
// Remember to handle err & early return
if (err) return console.log(dirPath + ' is not a directory.')
let notString = stats.isDirectory() ? "" : " not"
console.log(dirPath + ' is ' + notString + ' a directory.')
})
```
---
class: center, middle
# *Strawman much?*
Use a control-flow library!
** *We'll get there...* **
---
# Why not callbacks?
**Errors cannot be caught!\* **
```javascript
.
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
```javascript
// This will crash your server
isDir(__dirname, (err, stats) => {
throw new Error('Boom.')
})
.
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
```javascript
// This will crash your server
try {
isDir(__dirname, (err, stats) => {
throw new Error('Boom.')
})
} catch(err) {
}
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
```javascript
// This will crash your server
try {
isDir(__dirname, (err, stats) => {
throw new Error('Boom.')
})
} catch(err) {
// Nope.
}
```
\* ...
---
class: center, middle
# *Really? More strawmans?*
Just don't throw or pass the error.
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 1: No callback
```javascript
.
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 1: No callback
```javascript
// This will NOT crash your server
try {
isDir(dirPath, (err, stats) => {
console.log(new Error('Boom.').stack)
})
} catch(err) {
// Nope.
}
.
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 2: Pass error to callback
```javascript
function run(callback) {
// This will NOT crash your server
try {
isDir(dirPath, (err, stats) => {
callback(new Error('Boom.'))
})
} catch(err) {
// Nope.
}
}
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 3: Reality
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
if (err) return callback(null, false)
callback(null, stats.isDirectory())
})
}
.
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 3: Reality
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
if (err) return callback(null, false)
callback(null, stats.isDirectory())
})
}
isDir(__dirname, (err, isDir) => {
console.log(__dirname + ' is ' + isDir?"":" not" + ' a directory.')
})
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 3: Reality
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
if (err) callback(null, false)
callback(null, stats.isDirectory())
})
}
isDir(__dirname, (err, isDir) => {
console.log(__dirname + ' is ' + isDir?"":" not" + ' a directory.')
})
```
\* ...
---
class: center, middle
# **BOOM.**
Go directly to jail.
Do not pass Go.
Do not collect your bonus.
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 3: Reality
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
if (err) callback(null, false)
callback(null, stats.isDirectory())
})
}
isDir(__dirname, (err, isDir) => {
console.log(__dirname + ' is ' + isDir?"":" not" + ' a directory.')
})
.
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 3: Reality
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
if (err) callback(null, false)
callback(null, stats.isDirectory())
})
}
try {
isDir(__dirname, (err, isDir) => {
console.log(__dirname + ' is ' + isDir?"":" not" + ' a directory.')
})
} catch(e) {
}
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 3: Reality
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
if (err) callback(null, false)
callback(null, stats.isDirectory())
})
}
try {
isDir(__dirname, (err, isDir) => {
console.log(__dirname + ' is ' + isDir?"":" not" + ' a directory.')
})
} catch(e) {
// Nope.
}
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 3: Reality
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
if (err) callback(null, false)
callback(null, stats.isDirectory())
})
}
isDir(__dirname, (err, isDir) => {
console.log(__dirname + ' is ' + isDir?"":" not" + ' a directory.')
})
.
```
\* ...
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 3: Reality
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
if (err) callback(null, false)
callback(null, stats.isDirectory())
})
}
isDir(__dirname, (err, isDir) => {
console.log(__dirname + ' is ' + isDir?"":" not" + ' a directory.')
})
.
```
\* Unless you monkey-patch the runtime.
---
# Why not callbacks?
**Errors cannot be caught!\* **
Scenario 3: Reality
```javascript
function isDir(dirPath, callback) {
fs.stat(dirPath, (err, stats) => {
if (err) callback(null, false)
callback(null, stats.isDirectory())
})
}
trycatch(() => {
isDir(__dirname, (err, isDir) => {
console.log(__dirname + ' is ' + isDir?"":" not" + ' a directory.')
})
}, (err) => {
// Yup.
})
```
\* Unless you monkey-patch the runtime.
---
class: center, middle
# **Lesson?**
...
...
---
class: center, middle
# **Lesson?**
Use my `trycatch` library.
...
---
class: center, middle
# **Lesson?**
**No seriously,** use my `trycatch` library.
...
---
class: center, middle
# **Lesson?**
~~**No seriously,** use my `trycatch` library.~~
**Don't use callbacks.**
---
# Why not callbacks?
**The pyramid of doom**
```javascript
foo((err, a) => {
if (err) return callback(err)
bar(a, (err, b) => {
if (err) return callback(err)
baz(b, (err, c) => {
if (err) return callback(err)
// Uhh.....
})
})
})
```
---
# Why not callbacks?
**Even simple control-flows require complex non-standardized libraries**
```javascript
async.waterfall([
(callback) => {
callback(null, 'foo')
},
(callback, foo) => {
callback(null, 'bar')
},
(callback, bar) => {
callback(null, 'baz')
}
], (err, baz) => {
console.log(baz)
})
```
---
# Other requirements of the callback contract
---
# Other requirements of the callback contract
* Callbacks should always be passed last
---
# Other requirements of the callback contract
* Callbacks should always be passed last
* First argument is an error
---
# Other requirements of the callback contract
* Callbacks should always be passed last
* First argument is an error
* Second argument is the result
---
# Other requirements of the callback contract
* Callbacks should always be passed last
* First argument is an error
* Second argument is the result
* Never pass both
---
# Other requirements of the callback contract
* Callbacks should always be passed last
* First argument is an error
* Second argument is the result
* Never pass both
* Errors should be `instanceof` `Error`
---
# Other requirements of the callback contract
* Callbacks should always be passed last
* First argument is an error
* Second argument is the result
* Never pass both
* Errors should be `instanceof` `Error`
* Callbacks must never execute on the same event-loop tick
---
# Other requirements of the callback contract
* Callbacks should always be passed last
* First argument is an error
* Second argument is the result
* Never pass both
* Errors should be `instanceof` `Error`
* Callbacks must never execute on the same event-loop tick
* Return value should be ignored
---
# Other requirements of the callback contract
* Callbacks should always be passed last
* First argument is an error
* Second argument is the result
* Never pass both
* Errors should be `instanceof` `Error`
* Callbacks must never execute on the same event-loop tick
* Return value should be ignored
* Must never throw and always pass errors
---
# Other requirements of the callback contract
* Callbacks should always be passed last
* First argument is an error
* Second argument is the result
* Never pass both
* Errors should be `instanceof` `Error`
* Callbacks must never execute on the same event-loop tick
* Return value should be ignored
* Must never throw and always pass errors
* Must never be called more than once
---
# ~~Other requirements of the callback contract~~
* Callbacks should always be passed last
* First argument is an error
* Second argument is the result
* Never pass both
* Errors should be `instanceof` `Error`
* Callbacks must never execute on the same event-loop tick
* Return value should be ignored
* Must never throw and always pass errors
* Must never be called more than once
---
# Other reasons to not use callbacks
* Callbacks should always be passed last
* First argument is an error
* Second argument is the result
* Never pass both
* Errors should be `instanceof` `Error`
* Callbacks must never execute on the same event-loop tick
* Return value should be ignored
* Must never throw and always pass errors
* Must never be called more than once
---
class: center, middle
# **Still strawmanning?**
Control-flow libraries handle all this!
---
class: center, middle
# **Pop Quiz!**
Name one callback-based control-flow library
that handles all of the callback contract requirements.
---
class: center, middle
# **Answer:**
Only 1. `stepup`, which uses `trycatch`.
https://github.com/crabdude/stepup
---
class: center, middle
# **Lesson?**
...
...
---
class: center, middle
# **Lesson?**
Use my `stepup` library.
...
---
class: center, middle
# **Lesson?**
Use my `stepup` library **and my `trycatch` library.**
...
---
class: center, middle
# **Lesson?**
~~Use my `stepup` library **and my `trycatch` library.**~~
**Don't use callbacks.**
---
# What about `Promise`?
**Better...**
```javascript
function statDir(dirPath) {
// With pn/fs
return fs.stat(dirPath)
}
function statDir(dirPath) {
// With songbird
return fs.promise.stat(dirPath)
}
```
---
# What about `Promise`?
**Better...**
---
# What about `Promise`?
**Better...**
- Included in language: ES6, node v0.11.13, io.js v1.0
---
# What about `Promise`?
**Better...**
- Included in language: ES6, node v0.11.13, io.js v1.0
- Automatic error handling and propagation
---
# What about `Promise`?
**Better...**
- Included in language: ES6, node v0.11.13, io.js v1.0
- Automatic error handling and propagation
- Elegant chaining for control-flow
---
# What about `Promise`?
**Better...**
- Included in language: ES6, node v0.11.13, io.js v1.0
- Automatic error handling and propagation
- Elegant chaining for control-flow
- Expectations are guaranteed in spec:
---
# What about `Promise`?
**Better...**
- Included in language: ES6, node v0.11.13, io.js v1.0
- Automatic error handling and propagation
- Elegant chaining for control-flow
- Expectations are guaranteed in spec:
- Call only once
---
# What about `Promise`?
**Better...**
- Included in language: ES6, node v0.11.13, io.js v1.0
- Automatic error handling and propagation
- Elegant chaining for control-flow
- Expectations are guaranteed in spec:
- Call only once
- Pass real errors
---
# What about `Promise`?
**Better...**
- Included in language: ES6, node v0.11.13, io.js v1.0
- Automatic error handling and propagation
- Elegant chaining for control-flow
- Expectations are guaranteed in spec:
- Call only once
- Pass real errors
- Pass only error or result
---
# What about `Promise`?
**Better...**
- Included in language: ES6, node v0.11.13, io.js v1.0
- Automatic error handling and propagation
- Elegant chaining for control-flow
- Expectations are guaranteed in spec:
- Call only once
- Pass real errors
- Pass only error or result
- **Still very confusing for beginners**
---
# What about `Promise`?
**Promise Constructor**
```javascript
// Useful for complex or atypical flows
function wait(time) {
return new Promise((resolve, reject) => {
// setTimeout is not an err-back
setTimeout(resolve, time)
})
}
```
---
# What about `Promise`?
**Promise Constructor**
```javascript
// Or compatibility with callback APIs
function statDir(dirPath) {
return new Promise((resolve, reject) => {
fs.stat(dirPath, (err, stat) => {
if (err) return reject(err)
resolve(stat)
})
})
}
```
---
# What about `Promise`?
**Problem: Errors can silently fail!**
```javascript
// You won't know this threw
statDir(__dirname)
.then(stats => {
throw new Error('Boom.')
})
.then(someValue => {
// Nope.
})
```
---
# What about `Promise`?
**Simple control-flows are supported, but still not obvious**
```javascript
foo()
.
```
---
# What about `Promise`?
**Simple control-flows are supported, but still not obvious**
```javascript
foo()
.then(a => {
})
.
```
---
# What about `Promise`?
**Simple control-flows are supported, but still not obvious**
```javascript
foo()
.then(a => {
return bar(a)
})
.
```
---
# What about `Promise`?
**Simple control-flows are supported, but still not obvious**
```javascript
foo()
.then(a => {
return bar(a)
})
.then(bar => {
})
.
```
---
# What about `Promise`?
**Simple control-flows are supported, but still not obvious**
```javascript
foo()
.then(a => {
return bar(a)
})
.then(bar => {
return baz(c)
})
.
```
---
# What about `Promise`?
**Simple control-flows are supported, but still not obvious**
```javascript
foo()
.then(a => {
return bar(a)
})
.then(bar => {
return baz(c)
})
.then(result => console.log(result))
.
```
---
# What about `Promise`?
**Simple control-flows are supported, but still not obvious**
```javascript
foo()
.then(a => {
return bar(a)
})
.then(bar => {
return baz(c)
})
.then(result => console.log(result))
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
```
---
class: center, middle
# **Lesson?**
...
...
---
class: center, middle
# **Lesson?**
Use `Promise`.
...
---
class: center, middle
# **Lesson?**
Use `Promise` *for now.*
...
---
class: center, middle
# **Lesson?**
~~Use `Promise` *for now.*~~
**No, not really. Use async/await or async generators.**
---
# `async/await`
**Our hero!* **
```javascript
.
```
---
# `async/await`
**Our hero!* **
```javascript
foo().then(a => {
return bar(a)
})
.then(b => {
return baz(b)
})
.then(result => console.log(result))
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
let a = await foo()
return bar(a)
})
.then(b => {
return baz(b)
})
.then(result => console.log(result))
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
let a = await foo()
bar(a)
.then(b => {
return baz(b)
})
.then(result => console.log(result))
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
let a = await foo()
let b = await bar(a)
baz(b)
.then(result => console.log(result))
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
let a = await foo()
let b = await bar(a)
let result = await baz(b)
.then(result => console.log(result))
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
let a = await foo()
let b = await bar(a)
let result = await baz(b)
console.log(result)
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
async function main() {
let a = await foo()
let b = await bar(a)
let result = await baz(b)
console.log(result)
}
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
async function main() {
let a = await foo()
let b = await bar(a)
let result = await baz(b)
console.log(result)
}
main()
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
async function main() {
let a = await foo()
let b = await bar(a)
let result = await baz(b)
console.log(result)
}
main()
.then(result => console.log(result))
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
async function main(someArg) {
let a = await foo()
let b = await bar(a)
let result = await baz(b)
console.log(result)
}
main(someArg)
.then(result => console.log(result))
// ALWAYS remember to check for errors!
.catch(e => console.log(e.stack))
.
```
---
# `async/await`
**Our hero!* **
```javascript
async function main(someArg) {
let a = await foo()
let b = await bar(a)
let result = await baz(b)
console.log(result)
}
let result = await main(someArg)
.
```
---
# `async/await`
**Our hero!* **
```javascript
async function main(someArg) {
let a = await foo()
let b = await bar(a)
let result = await baz(b)
console.log(result)
}
async ()=> {
let result = await main(someArg)
}()
```
---
# `async/await`
**Our hero!* **
```javascript
async function main(someArg) {
let a = await foo()
let b = await bar(a)
let result = await baz(b)
console.log(result)
}
async ()=> {
let result = await main(someArg)
console.log(result)
}()
```
---
# `async/await`
**Our hero!* **
```javascript
async function main(someArg) {
let a = await foo()
let b = await bar(a)
let result = await baz(b)
console.log(result)
}
async ()=> {
try {
let result = await main(someArg)
} catch(e) {
console.log(e.stack)
}
console.log(result)
}()
```
---
# `async/await`
**Synchronous-style Parallel IO**
```javascript
async function main(someArg) {
// Wait on foo, bar and baz in parallel
let [a, b, c] = await Promise.all([foo(someArg), bar(), baz()])
return a + b + c
}
```
---
# `async/await`
**Await on Non-Promise values**
```javascript
async function main(someArg) {
// Wait on foo, bar and baz in parallel
let [a, b, c] = await Promise.all([foo(someArg), bar(), baz()])
return a + b + c
}
```
*Note: It's intentional that the code above is the same!*
---
# Why is `async/await` SUPER AWESOME?!
1. It forces a distinction between synchronous and asynchronous functions!
1. Automatically handles the async contract
1. It composes with existing language features
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
- The phase between blocking IO and async IO
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
- The phase between blocking IO and async IO
- Typically, used to construct objects
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
- The phase between blocking IO and async IO
- Typically, used to construct objects
- E.g., `http.createServer(..)`
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
- The phase between blocking IO and async IO
- Typically, used to construct objects
- E.g., `http.createServer(..)`
- Initialize Phase
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
- The phase between blocking IO and async IO
- Typically, used to construct objects
- E.g., `http.createServer(..)`
- Initialize Phase
- Async IO only
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
- The phase between blocking IO and async IO
- Typically, used to construct objects
- E.g., `http.createServer(..)`
- Initialize Phase
- Async IO only
- E.g., `await http.promise.listen(8000)`
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
- The phase between blocking IO and async IO
- Typically, used to construct objects
- E.g., `http.createServer(..)`
- Initialize Phase
- Async IO only
- E.g., `await http.promise.listen(8000)`
- Running Phase
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
- The phase between blocking IO and async IO
- Typically, used to construct objects
- E.g., `http.createServer(..)`
- Initialize Phase
- Async IO only
- E.g., `await http.promise.listen(8000)`
- Running Phase
- Ready to receive requests, respond to external events, etc...
---
# `async/await`
**Lifecycle Phases:**
- Require Phase
- Blocking `*Sync` IO acceptable
- Must be completed by end of the main tick
- E.g., `require('fs')`, etc...
- Configure Phase
- The phase between blocking IO and async IO
- Typically, used to construct objects
- E.g., `http.createServer(..)`
- Initialize Phase
- Async IO only
- E.g., `await http.promise.listen(8000)`
- General Phase
- Ready to receive requests, respond to external events, etc...
- E.g., `app.get('*', routeHandler)`
---
# `async/await`
**Separation of Async and Sync lifecycle phases**
```javascript
async function main(someArg) => {
let a = await foo(someArg)
let b = await bar(a)
let c = await baz(b)
return result
}
async ()=> {
try {
let result = await main(someArg)
} catch(e) {
console.log(e.stack)
}
}()
```
---
# `async/await`
**Separation of Async and Sync lifecycle phases**
```javascript
async function main(someArg) => {
// General Phase
let a = await foo(someArg)
let b = await bar(a)
let c = await baz(b)
return result
}
async ()=> {
try {
let result = await main(someArg)
} catch(e) {
console.log(e.stack)
}
}()
```
---
# `async/await`
**Separation of Async and Sync lifecycle phases**
```javascript
// index.js
// Require Phase
let main = require('./main')
async ()=> {
try {
let result = await main(someArg)
} catch(e) {
console.log(e.stack)
}
}()
```
---
# `async/await`
**Separation of Async and Sync lifecycle phases**
```javascript
// index.js
// Require Phase
let main = require('./main')
// Initialize Phase
main(someArg).catch(err => console.log(err.stack))
```
---
# `async/await`
**Separation of Async and Sync lifecycle phases**
```javascript
// index.js
// Require Phase
let main = require('./main')
// Configure Phase
process.on('uncaughtException', function(err) {
console.log('uncaughtException: \n\n', err.stack)
// IMPORTANT! (optionally, soft exit)
process.exit()
})
// Initialize Phase
main(someArg).catch(err => console.log(err.stack))
```
---
# `async/await`
**Separation of Async and Sync lifecycle phases**
```javascript
// index.js
// Require Phase
let main = require('./main')
// Configure Phase
process.on('uncaughtException', function(err) {
console.log('uncaughtException: \n\n', err.stack)
// IMPORTANT! (optionally, soft exit)
process.exit()
})
process.on('unhandledRejection', (err, rejectedPromise) => {
console.log('unhandledRejection: \n\n', err.stack)
})
// Initialize Phase
main(someArg).catch(err => console.log(err.stack))
```
---
# `async/await`
**Separation of Async and Sync lifecycle phases**
```javascript
// index.js
// Require Phase
let app = require('./app')
// Configure Phase
process.on('uncaughtException', function(err) {
console.log('uncaughtException: \n\n', err.stack)
// IMPORTANT! (optionally, soft exit)
process.exit()
})
process.on('unhandledRejection', (err, rejectedPromise) => {
console.log('unhandledRejection: \n\n', err.stack)
})
// Initialize Phase
app.initialize().catch(err => console.log(err.stack))
```
---
# `async/await`
**Even safer with `trycatch`**
```javascript
// index.js
// Require Phase
let app = require('./app')
// Initialize Phase
app.initialize().catch(err => console.log(err.stack))
```
---
# `async/await`
**Even safer with `trycatch`**
```javascript
// index.js
// Require Phase
let app = require('./app')
require('trycatch')
// Initialize Phase
app.initialize().catch(err => console.log(err.stack))
```
---
# `async/await`
**Even safer with `trycatch`**
```javascript
// index.js
// Require Phase
let app = require('./app')
require('trycatch')
// Configure Phase
process.on('uncaughtException', handleErrorAndExit)
process.on('unhandledRejection', handleError)
// Initialize Phase
app.initialize().catch(err => console.log(err.stack))
```
---
# `async/await`
**Even safer with `trycatch`**
```javascript
// index.js
// Require Phase
let app = require('./app')
require('trycatch')
// Configure Phase
process.on('uncaughtException', handleErrorAndExit)
process.on('unhandledRejection', handleError)
process.on('unhandledApplicationException', handleError)
// Initialize Phase
app.initialize().catch(err => console.log(err.stack))
```
---
# `async/await`
**`trycatch` also supports long-stack-traces**
```javascript
// index.js
// Require Phase
let app = require('./app')
let trycatch = require('trycatch')
// Configure Phase
process.on('uncaughtException', handleErrorAndExit)
process.on('unhandledRejection', handleError)
process.on('unhandledApplicationException', handleError)
if (process.env.NODE_ENV === 'development') {
trycatch.configure({'long-stack-traces'})
}
// Initialize Phase
app.initialize().catch(err => console.log(err.stack))
```
---
# `async/await`
**`trycatch` also supports long-stack-traces**
![:scale 100%](images/trycatch-long-stack-trace.png "Long Stak Traces")
---
# `async/await`
**Using `async/await` today with Async Generators (`function*()/yield`)**
- Supported today with `--harmony` flag in node v0.11.13, io.js v1.0
- Supported today **without a flag** in node v4.0
- Requires a library: `blubird.coroutine(function*(){})`
```javascript
function* main(someArg) {
let a = yield foo(someArg)
let b = yield bar(a)
let c = yield baz(b)
return result
}
bluebird.coroutine(function*() {
try {
let result = yield main()
} catch(e) {
console.log(e.stack)
}
})
```
---
class: center, middle
# Questions?
</textarea>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/highlight.min.js"></script>
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js">
</script>
<script>
remark.highlighter.engine = hljs
remark.macros.scale = function (percentage) {
var url = this
return '<img src="' + url + '" style="width: ' + percentage + '" />'
}
var slideshow = remark.create({
highlightStyle: 'tomorrow-night-bright'
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment