See "part 1: A taste of nodejs generators"
I played with generator functions to learn more about their properties.
Logging intermediate values
Function generators can be used to add logging to functions without tight coupling.
For example, the generator can simply yield
a value to be processed by the outside caller,
and the outside caller might log it.
1 | // generator function |
generated value 1
generated value 2
generated value 4
generated value 9
yield
is synchronous
When a generator yields a value, it happens synchronously, you can test this by adding a couple of functions that place other messages on the event queue
1 | // node --harmony index.js |
generated value 1
generated value 2
generated value 4
generated value 9
trying to print between yield and return
trying to print between yield and return again
generator and caller work in parallel
You can think of the generator and its caller as executing in turns at the same time.
The generator surrenders to the caller using yield
and the caller resumes
the generator by calling next()
. You can see by inserting print statements
into both generator and caller functions.
1 | function *square() { |
starting generator
yielding 1
got back { value: 1, done: false }
starting generator
yielding 2
got back { value: 2, done: false }
starting generator
all done
got back { value: undefined, done: true }
caller done
caller can transform yielded values
yield
returns a value, which can be transformed by the caller and
sent back to the generator via next()
call. For example, lets double
the numbers before printing
1 | function *square() { |
2
4
8
18
yield
without generator
If you try to use yield
keyword outside a generator function, Node throws an error
1 | function square() { |
// prints
ReferenceError: yield is not defined
at square (/Users/gbahmutov/git/training/node/es6/test2/index.js:2:5)
Broken generator cannot be mended
If the generator throws an Error, it cannot be restarted
1 | function *square() { |
starting generator
yielding 1
got back { value: 1, done: false }
throwing an exception
fixing generator { value: 1, done: false }
fixing generator { value: 1, done: false }
caller done
Bonus: co
module
See callbacks vs generators by TJ Holowaychuk that shows simplifying callback hell using generators. He recommends his NPM module called co that wraps around promises, callbacks etc yielded from the generator to drastically simplify asynchronous processing. For example, here is a code sample that downloads a page, then downloads all links, then collects all content type fields, all executed asynchronously, but in a very clean function.
1 | function showTypes(fn) { |