Coroutines are extremely powerful constructs that make writing asynchronous code dead simple. In this talk, we'll go over how we can implement coroutines in ES2015 using generators and promises, as well as tools and libraries that allow you to leverage coroutines today. We'll also walk through some sample use cases that showcase the power of coroutines.
Example code is available at https://github.com/traviskaufman/co-talk-examples
1. Dead-Simple Async
Control Flow with
Coroutines
by Travis Kaufman (@traviskaufman)
github.com/traviskaufman/co-talk-examples
2. Outline
Define the problem
Async control flow in NodeJS
Present the solution
Coroutines (surprise!)
Explore the implementation
How coroutines work under the hood
Coroutine libraries
Start using them in your apps today!
(time permitting) Advanced usage
Sample code showing where coroutines really shine
5. Callbacks are UNINTUITIVE
Simple Program: Get GH Username, print out 10 most recently pushed repos
https://github.com/traviskaufman/co-talk-examples/blob/master/01-raw-callbacks.js
6. Callbacks are UNINTUITIVE
Simple Program: Get GH Username, print out 10 most recently pushed repos
https://github.com/traviskaufman/co-talk-examples/blob/master/01-raw-callbacks.js
Code duplication
7. Callbacks are UNINTUITIVE
Simple Program: Get GH Username, print out 10 most recently pushed repos
https://github.com/traviskaufman/co-talk-examples/blob/master/01-raw-callbacks.js
Code duplication
“Diagonal Development” / Pyramid of Doom / Callback Hell / etc
8. Callbacks are UNINTUITIVE
Simple Program: Get GH Username, print out 10 most recently pushed repos
https://github.com/traviskaufman/co-talk-examples/blob/master/01-raw-callbacks.js
Code duplication
Refactoring callbacks means
jumping around code to see logical
flow of execution :((
“Diagonal Development” / Pyramid of Doom / Callback Hell / etc
10. Callbacks are UNINTUITIVE
The “solution”: use a library (e.g. caolan/async, a.k.a. the jQuery of NodeJS)
Only have to handle this in one place! :D
https://github.com/traviskaufman/co-talk-examples/blob/master/02-async-lib-callbacks.js
11. Callbacks are UNINTUITIVE
The “solution”: use a library (e.g. caolan/async, a.k.a. the jQuery of NodeJS)
Need to be familiar with “async.waterfall”
API Change to accommodate lib usage?
Only have to handle this in one place! :D
https://github.com/traviskaufman/co-talk-examples/blob/master/02-async-lib-callbacks.js
12. Promises to the Rescue!
https://github.com/traviskaufman/co-talk-examples/blob/master/03-raw-promises.js
No triangles/pyramids/hells/doom/etc.
Error handling separated from general logic
13. Promises to the Rescue! but...
https://github.com/traviskaufman/co-talk-examples/blob/master/03-raw-promises.js
No triangles/pyramids/hells/doom/etc.
Error handling separated from general logic
API Weirdness still...
Still requires handler functions for promise settling
14. Can We Do Better?
Readability of synchronous code
I/O Efficiency of Asynchronous Code
16. YES! Introducing Coroutines
● coroutine(gen: GeneratorFunction) => Promise
● generator function yields Promises
● values from resolved promises are assigned
● errors from rejected promises are thrown within generator
○ note: could use try/catch inside generator to call handleError()
● Returns Promise for easy interop with other async code
● Best of both worlds! Readability/Intuitiveness + Efficiency/Non-blocking I/O
https://github.com/traviskaufman/co-talk-examples/blob/master/04-co-promises.js
18. Coroutines = “Cooperative Routines”
Cooperative threads are
responsible for explicitly telling
executor when they should be
suspended
Differs from preemptive threads
which rely on executor to
suspend/resume them
Reference (Java-based):
http://www.cafeaulait.org/course/
week11/32.html
https://www.cs.mtu.edu/~shene/NSF-3/e-Book/FUNDAMENTALS/thread-yield.jpg
19. Coroutines = “Cooperative Routines”
Generators provide cooperation
through the yield keyword
Explicitly tells IO-Loop (uv,
etc.) to suspend execution
Promises provide the routines
Scheduled and run
asynchronously by IO-Loop
Generators + Promises =
Cooperation + Routines =
Coroutines!
https://www.cs.mtu.edu/~shene/NSF-3/e-Book/FUNDAMENTALS/thread-yield.jpg
yield
new Promise(...)
21. Coroutine Libraries: tj/co
My personal favorite
Supports thunks as well as promises
Supports yielding arrays/objects
(Promise.race), as well as generators
(delegation)
https://github.com/tj/co
22. Coroutine Libraries: mozilla/task.js
Similar to co
Very powerful built-in scheduler
Adds cancellation to promises
Makes coroutines look a lot like thread-based
scheduling
http://taskjs.org/
23. “But wait, I need ES2015 for this!”
Use babelJS (https://babeljs.io/) to transpile
your code!
Use the --harmony-generators flag with
v0.11+ to enable generators (or just --
harmony)
Check out petkaantonov/bluebird for an
awesome promise polyfill/superset.
26. Additional Resources
MDN reference for generator functions
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
Awesome Promise tutorial from HTML5Rocks
http://www.html5rocks.com/en/tutorials/es6/promises/
“Promises and Generators: Control Flow Utopia” - Great presentation by Forbes Lindesay
http://pag.forbeslindesay.co.uk/#/
“No Promises: Asynchronous Javascript with only generators”
http://www.2ality.com/2015/03/no-promises.html
Axel Rauschmayer takes it one step further and shows how you can use generators to write
async code without the need for promises. Super interesting stuff!
one of the things we software engineers take most seriously is maintainability and readability. You want your code to represent the logical flow of steps to solve the problem at hand.
Mention how I <3 Async and, like jQuery, it is an amazing library
Mention how I <3 Async and, like jQuery, it is an amazing library
Mention how I <3 Async and, like jQuery, it is an amazing library