Skip to content

Instantly share code, notes, and snippets.

@alanshaw
Last active September 14, 2016 08:16
Show Gist options
  • Save alanshaw/ac5b1503ce41db692c27aaa1390ac53d to your computer and use it in GitHub Desktop.
Save alanshaw/ac5b1503ce41db692c27aaa1390ac53d to your computer and use it in GitHub Desktop.
How watt (the generator based control flow library) works
// 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...
@olizilla
Copy link

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?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment