Last active
September 14, 2016 08:16
-
-
Save alanshaw/ac5b1503ce41db692c27aaa1390ac53d to your computer and use it in GitHub Desktop.
How watt (the generator based control flow library) works
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is how watt (https://www.npmjs.com/package/watt) works: | |
// The watt factory function takes a generator as it's parameter | |
const watt = (generator) => { | |
// ...and returns a function you can call to RUN it | |
return () => { | |
// Create a new instance of the generator | |
const g = generator(next) | |
// Create a callback your code will give to all your node style async functions | |
// Like this: `fs.readFile(path, next)` | |
function next (err, res) { | |
// If an error occurred, call the generator throw function which will | |
// throw it in your resumed code, allowing you to try/catch it | |
// Like this: `try { yield fs.readFile(path, next) } catch (err) { console.log(err) }` | |
if (err) return g.throw(err) | |
// If no error, pass back the result of the async operation to your resumed code | |
// It allows you to assign results of async operations to variables! | |
// Like this: `const contents = yield fs.readFile(path, next)` | |
g.next(res) | |
} | |
// Start the generator running... | |
return g.next() | |
} | |
} | |
// THATS IT! | |
// --- | |
// Here's how you use it: | |
const fs = require('fs') | |
// Create a new watt function we can use to run our code | |
const runReadFile = watt(function* (next) { | |
try { | |
// Try changing './watt.js' to a file that doesn't exist! | |
const contents = yield fs.readFile('./watt.js', 'utf8', next) | |
console.log(contents) | |
} catch (err) { | |
console.error('Failed to read file', err) | |
} | |
}) | |
runReadFile() // prints out contents of ./watt.js | |
// --- | |
// Another example: | |
// asyncCount is a cool library which will callback with an incremented number | |
// each time it is called | |
// | |
// Like this: | |
// ``` | |
// const counter = asyncCount(0) // Initialise with a starting number | |
// | |
// counter((err, i) => { | |
// console.log(i) // 0 | |
// counter((err, i) => { | |
// console.log(i) // 1 | |
// }) | |
// }) | |
// ``` | |
const asyncCount = (i, timeout = 1000) => { | |
return (cb) => setTimeout(() => cb(null, i++), timeout) | |
} | |
// Create a new watt function we can use to run our code | |
const runCountUp = watt(function* (next) { | |
const counter = asyncCount(0) | |
// An infinite loop! | |
while (true) { | |
// Wait for the result of asyncCount and assign to i | |
let i = yield counter(next) | |
console.log(i) | |
} | |
}) | |
runCountUp() // Counts up, 0, 1, 2, 3, 4... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
it looks like
runCountUp()
would return immediately. How would your calling code use this to wait for some useful async result without a callback? (is that the point of this? fibers / await style, sync looking async without blocking everything?)