Skip to content

Instantly share code, notes, and snippets.

@drodsou
Last active March 30, 2017 09:36
Show Gist options
  • Save drodsou/75bd6d9ab37079b26588a5792ef9f5e1 to your computer and use it in GitHub Desktop.
Save drodsou/75bd6d9ab37079b26588a5792ef9f5e1 to your computer and use it in GitHub Desktop.
Generator deasync pattern
/**
* returns a function that runs an async generator (one which yields async functions), usings auto yield/next thanks to an 'args.next'
* The created function expects as parameter an optional object with a {cb:callbackFn} property plus aditional custom arguments
* Can also make a onliner gen runner with it: function runAsyncGen(gen, args) { newAsyncFn(gen)(args) }
*/
function createAsyncFn (gen) {
return function(args={}, cb) {
//var cb = (typeof args === 'function') ? args : args.cb
it = gen(args) // create iterator from generator, and pass a common object to communicate
args.next = (res)=>{ // pre made callback to pass to async funcions inside generator to keep going on
let ret = it.next(res)
if (ret.done && typeof cb === 'function') cb(ret.value) // "return" statement is another "yield" with .done = true
}
args.nextIfOK = (err,res)=>{ // to quickly handle (err, res) standard nodejs returns inside a try/catch
if (!err) args.next(res)
else it.throw(new Error(err))
}
it.next() // start iterator
}
}
// -------------------------------- EXAMPLE
// Nodejs async readline in a sync fashion
// the 'args' parameter here is the args parameter passed to the funcion, plus a .next function of the current iterator
var promptUser = createAsyncFn( function* (args) {
var r = require('readline')
var rl = r.createInterface({input: process.stdin, output: process.stdout })
// magic here
var answerA = yield rl.question(`Hello ${args.name}, do you want this? `, args.next) // or somting like (err, res)=>args.next({err,res})
console.log("mmm, let me think about it...")
yield setTimeout(args.next, 1000)
var answerB = yield rl.question('are you sure? ', args.next)
rl.close() // readline boilerplate
return {answerA, answerB} // the last 'yield'
})
// now make use of it
promptUser({ name:'Neo', cb:(r)=>{
console.log('\nAnswers:',r)
}})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment