- Available in ES6 Harmony
- Present in Node
0.11 unstableand above
- Enable via the
Generators are constructor functions for iterators.
Define an iterator constructor function (i.e. a generator) with a
* after the
The iterator instance returned from a generator function has a method
next method can be called multiple times on a generator, and each time it will return the result of each consecutuve iteration.
yield keyword inside the generator to emit this result.
next is called the function is invoked and it returns an object with
done fields. The
value field contains whatever was yielded, and the boolean
done indicates whether the function has returned/completed yet or not.
Importantly unlike normal non-blocking JS, execution inside the generator function is blocked immediately after a yield, and only resumes when
next is called again.
Async flow control with generators
Example: 'Callback hell' https://github.com/jedrichards/portfolio/blob/master/api/api/routes/auth-routes.js
next returns its yielded value synchronously, there's nothing intrinsically async about generators.
But where things get interesting is when the yielded value is something other than a primitive value. For example some sort of object that represents an async operation like a promise or a thunk.
When used in this way, usually together with a generator flow control library like
co, we can describe sets of sequential async operations that look like sync code and thus avoid messy nested callbacks and fiddly error handling
The above example works because
co can recognise a thunk being yielded and knows how to handle it. The full list of yielded objects that
co can work with:
- More generators (nesting)
- Arrays & objects (for parallel execution)
Flow control using generators turns out to be a nice pattern for web app middleware.
We can use the
yield keyword to avoid nested callbacks in middleware (for example when interacting with other async resources), and create an 'onion skin' like structure. Each middleware yields to the next until a middleware function returns at which point the response is sent and the middleware stack unwinds allowing each middleware to perform any final "post response" actions. Middleware state is retained pre and post response by lieu of the simple fact we're still in the same function scope.
KoaJS uses co under the hood so we can take advantage of the flow control it provides to construct nested sets of sequential or parallel middleware tasks using thunks, promises and generator syntax.
Error handling is also much improved. No more messy testing
err function arguments like traditional callbacks. Generator and yield syntax means that the call stack is not disrupted like with async code (remember that inside generators syncronous code is just blocked, not left behind) this means that
try catch blocks work as expected.