James Hunter
@cccc00
ES7 Async Functions
But, How did we get here?
We Divided Cats...
Hologrammed Some JS...
A Man Love Promises...
I <3 Promises Too
Don't worry Ben
I <3 Promises Too
You will see why in about 2 minutes
Lets Create a Comment
Lets Create a Comment
- Check if user can comment
- Check if comment is valid
- Post comment to server
- If successful return comment
Synchronous World
function createComment (comment) {
const canComment = userCanCreateComment(); // 1 Permission Check
if (!canComment) throw new Error("User cant comment");
const validComment = commentIsValid(comment); // 2 Validate Comment
if (!validComment) throw new Error("Invalid Comment");
const success = postNewComment(comment); // 3 Post to server
if (!success) throw new Error("Could not save post");
return comment; // 4 return comment
}Synchronous World
- Very close to our list of things
- Easy to follow
- Easy to extend/modify
- Arguably maintainable
- Composable (with side effects)
Synchronous World
Callbacks
function createComment (comment, callback) {
try {
userCanCreateComment((err) => { // 1 Permission Check
// if err
commentIsValid(comment, (err) => { // 2 Validate Comment
// if err
postNewComment(comment, (err) => { // 3 Post to server
// if err
if (callback) callback(comment); // 4 return comment
});
});
});
} catch (err) {
// do something with error
}
}Callbacks
- Callback hell and the Pyramid of Doom
- Higher order functions nested in higher order functions
- Dealing with raised errors suck
- Convention based ie: (error, result) => {}
Callbacks
function createComment (comment, callback) {
try {
userCanCreateComment((err) => { // 1 Permission Check
// if err
commentIsValid(comment, (err) => { // 2 Validate Comment
// if err
postNewComment(comment, (err) => { // 3 Post to server
// if err
if (callback) callback(comment); // 4 return comment
});
});
});
} catch (err) {
// do something with error
}
}Doom
Promises
function createComment (comment) {
return new Promise ((resolve, reject) => {
userCanCreateComment() // 1 Permission Check
.then(commentIsValid(comment), handleBadPermission) // 2 Validate Comment
.then(postNewComment(comment), handleBadComment) // 3 Post to Server
.then(() => resolve(comment), handleBadPost) // 4 Return Comment
.catch(err => reject(err, data))
})
}
// but we obscure the complexity away
function commentIsValid(comment) {
return function() {
return new Promise ((resolve, reject) => {
// the thing that actually checks if
// the comment is valid
return validatorThing(comment)
})
};
}Promises
- Notoriously hard to debug
- Obscures complexity
- Applicative Functor / Monad
- The bigger the chain, the easier the fail
Enter Coroutines
What is a Coroutine ?
What is a Coroutine ?
A coroutine is a function that can suspend its execution (yield/wait) until the given Yield Instruction is completed
Coroutine w/ Generator
function createComment (comment) {
return coroutine(function * () {
const canComment = yield userCanCreateComment(); // 1 Permission Check
if (!canComment) throw new Error("User cant comment");
const validComment = yield commentIsValid(comment); // 2 Validate Comment
if (!validComment) throw new Error("Invalid Comment");
const success = yield postNewComment(comment); // 3 Post to Server
if (!success) throw new Error("Could not save post");
return comment; // 4 Return Comment
})();
}Synchronous World
function createComment (comment) {
const canComment = userCanCreateComment(); // 1 Permission Check
if (!canComment) throw new Error("User cant comment");
const validComment = commentIsValid(data); // 2 Validate Comment
if (!validComment) throw new Error("Invalid Comment");
const success = postNewComment(comment); // 3 Post to server
if (!success) throw new Error("Could not save post");
return comment; // 4 return comment
}Coroutine w/ Generator
- Closest yet to our synchronous example
- Useable today Bluebird.coroutine(generator)
- Must yield to a Promise
- Leverages promises in a new powerful way
- Need to polyfill generators (Regenerator)
- Coroutine returns a function that returns a Promise
ES7 Async & Await
async function createComment (comment) {
const canComment = await userCanCreateComment(); // 1 Permission Check
if (!canComment) throw new Error("User cant comment");
const validComment = await commentIsValid(comment); // 2 Validate Comment
if (!validComment) throw new Error("Invalid Comment");
const success = await postNewComment(comment); // 3 Post to Server
if (!success) throw new Error("Could not save post");
return comment; // 4 Return Comment
}ES7 Async & Await
function createComment (comment) {
const canComment = userCanCreateComment(); // 1 Permission Check
if (!canComment) throw new Error("User cant comment");
const validComment = commentIsValid(comment); // 2 Validate Comment
if (!validComment) throw new Error("Invalid Comment");
const success = postNewComment(comment); // 3 Post to Server
if (!success) throw new Error("Could not save post");
return comment; // 4 Return Comment
}Synchronous World
function createComment (comment) {
const canComment = userCanCreateComment(); // 1 Permission Check
if (!canComment) throw new Error("User cant comment");
const validComment = commentIsValid(comment); // 2 Validate Comment
if (!validComment) throw new Error("Invalid Comment");
const success = postNewComment(comment); // 3 Post to Server
if (!success) throw new Error("Could not save post");
return comment; // 4 Return Comment
}ES7 Async & Await
- Extremely close to our synchronous example
- Useable today with transpilers (Babel)
- Does the same thing as our Coroutine example
- Must await on promises
Coroutines
- rationalize asynchronous code closer to how we think
- utilize asynchronous functions similar to synchronous ones
- leverage promises in a less error prone way
- are composable in other coroutines
Resources
- Slides – slides.com/jameshunter/async-await
- Coroutines – en.wikipedia.org/wiki/Coroutine
- Bluebird – github.com/petkaantonov/bluebird
- Babel – babeljs.io
- tc39 Proposal – github.com/tc39/ecmascript-asyncawait
- Compatibility – kangax.github.io/compat-table/es7
- Twitter – James Hunter – @cccc00
Async & Await
By James Hunter
Async & Await
- 935