UNPKG

control-flow

Version:

Turns asynchronous function into synchronous

87 lines (77 loc) 2.79 kB
require('fibers') var flow = module.exports = {} // Creates special, fiber-aware asynchronous callback resuming current fiber when it will be finished. flow.promise = function(){ var fiber = Fiber.current if(!fiber) throw "no current Fiber, promise can'b be used without Fiber!" return function(){ var thatArguments = arguments // Wrapping in nextTick as a safe measure against not asynchronous usage. process.nextTick(function(){ if(thatArguments[0]){ // Resuming fiber and throwing error. fiber.throwInto(thatArguments[0]) }else{ // Resuming fiber and returning result. fiber.run(thatArguments[1]) } }) } } // Takes function and returns its synchronized version, it's still backward compatible and // can be used as asynchronous `syncFn = sync(asyncFn)`. // // Or You can provide object and it will synchronize its functions `sync(obj, fname1, fname2, ...)`. // // New synchronized version of function is backward compatible and You may call it as usual with // explicit callback or inside of `fiber` with `yield` keyword. flow.sync = function(){ if(arguments.length > 1){ // Synchronizing functions of object. var obj = arguments[0] for(var i = 1; i < arguments.length; i++){ var fname = arguments[i] var fn = obj[fname] if(!fn) throw new Error("object doesn't have '" + fname + "' function!") obj[fname] = flow.sync(fn) } }else{ var fn = arguments[0] // Preventing function to be synchronized twice. if(fn._synchronized) return fn // Synchronized version of function. var sFn = function(){ // Using fibers only if there's active fiber and callback not provided explicitly. if(Fiber.current && (typeof arguments[arguments.length-1] !== 'function')){ // Calling asynchronous function with our special fiber-aware callback. Array.prototype.push.call(arguments, flow.promise()) return fn.apply(this, arguments) }else{ // If there's no active fiber or callback provided explicitly we call original version. return fn.apply(this, arguments) } } // Marking function as synchronized. sFn._synchronized = true return sFn } } // Executes `callback` within `Fiber`, when it finish it will call `done` callback. // If error will be thrown during execution, this error will be catched and passed to `done`, // if `done` not provided it will be just rethrown. flow.fiber = function(callback, done){ var that = this Fiber(function(){ if (done) { try { callback.call(that) done() } catch (error){ done(error) } } else { // Don't catch errors if done not provided! callback.call(that) } }).run() }