diff options
Diffstat (limited to 'node_modules/when/node.js')
-rw-r--r-- | node_modules/when/node.js | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/node_modules/when/node.js b/node_modules/when/node.js new file mode 100644 index 000000000..61d9453ff --- /dev/null +++ b/node_modules/when/node.js @@ -0,0 +1,282 @@ +/** @license MIT License (c) copyright 2013 original author or authors */ + +/** + * Collection of helpers for interfacing with node-style asynchronous functions + * using promises. + * + * @author Brian Cavalier + * @contributor Renato Zannon + */ + +(function(define) { +define(function(require) { + + var when = require('./when'); + var _liftAll = require('./lib/liftAll'); + var setTimer = require('./lib/env').setTimer; + var slice = Array.prototype.slice; + + var _apply = require('./lib/apply')(when.Promise, dispatch); + + return { + lift: lift, + liftAll: liftAll, + apply: apply, + call: call, + createCallback: createCallback, + bindCallback: bindCallback, + liftCallback: liftCallback + }; + + /** + * Takes a node-style async function and calls it immediately (with an optional + * array of arguments or promises for arguments). It returns a promise whose + * resolution depends on whether the async functions calls its callback with the + * conventional error argument or not. + * + * With this it becomes possible to leverage existing APIs while still reaping + * the benefits of promises. + * + * @example + * function onlySmallNumbers(n, callback) { + * if(n < 10) { + * callback(null, n + 10); + * } else { + * callback(new Error("Calculation failed")); + * } + * } + * + * var nodefn = require("when/node/function"); + * + * // Logs '15' + * nodefn.apply(onlySmallNumbers, [5]).then(console.log, console.error); + * + * // Logs 'Calculation failed' + * nodefn.apply(onlySmallNumbers, [15]).then(console.log, console.error); + * + * @param {function} f node-style function that will be called + * @param {Array} [args] array of arguments to func + * @returns {Promise} promise for the value func passes to its callback + */ + function apply(f, args) { + return _apply(f, this, args || []); + } + + function dispatch(f, thisArg, args, h) { + var cb = createCallback(h); + try { + switch(args.length) { + case 2: f.call(thisArg, args[0], args[1], cb); break; + case 1: f.call(thisArg, args[0], cb); break; + case 0: f.call(thisArg, cb); break; + default: + args.push(cb); + f.apply(thisArg, args); + } + } catch(e) { + h.reject(e); + } + } + + /** + * Has the same behavior that {@link apply} has, with the difference that the + * arguments to the function are provided individually, while {@link apply} accepts + * a single array. + * + * @example + * function sumSmallNumbers(x, y, callback) { + * var result = x + y; + * if(result < 10) { + * callback(null, result); + * } else { + * callback(new Error("Calculation failed")); + * } + * } + * + * // Logs '5' + * nodefn.call(sumSmallNumbers, 2, 3).then(console.log, console.error); + * + * // Logs 'Calculation failed' + * nodefn.call(sumSmallNumbers, 5, 10).then(console.log, console.error); + * + * @param {function} f node-style function that will be called + * @param {...*} [args] arguments that will be forwarded to the function + * @returns {Promise} promise for the value func passes to its callback + */ + function call(f /*, args... */) { + return _apply(f, this, slice.call(arguments, 1)); + } + + /** + * Takes a node-style function and returns new function that wraps the + * original and, instead of taking a callback, returns a promise. Also, it + * knows how to handle promises given as arguments, waiting for their + * resolution before executing. + * + * Upon execution, the orginal function is executed as well. If it passes + * a truthy value as the first argument to the callback, it will be + * interpreted as an error condition, and the promise will be rejected + * with it. Otherwise, the call is considered a resolution, and the promise + * is resolved with the callback's second argument. + * + * @example + * var fs = require("fs"), nodefn = require("when/node/function"); + * + * var promiseRead = nodefn.lift(fs.readFile); + * + * // The promise is resolved with the contents of the file if everything + * // goes ok + * promiseRead('exists.txt').then(console.log, console.error); + * + * // And will be rejected if something doesn't work out + * // (e.g. the files does not exist) + * promiseRead('doesnt_exist.txt').then(console.log, console.error); + * + * + * @param {Function} f node-style function to be lifted + * @param {...*} [args] arguments to be prepended for the new function @deprecated + * @returns {Function} a promise-returning function + */ + function lift(f /*, args... */) { + var args1 = arguments.length > 1 ? slice.call(arguments, 1) : []; + return function() { + // TODO: Simplify once partialing has been removed + var l = args1.length; + var al = arguments.length; + var args = new Array(al + l); + var i; + for(i=0; i<l; ++i) { + args[i] = args1[i]; + } + for(i=0; i<al; ++i) { + args[i+l] = arguments[i]; + } + return _apply(f, this, args); + }; + } + + /** + * Lift all the functions/methods on src + * @param {object|function} src source whose functions will be lifted + * @param {function?} combine optional function for customizing the lifting + * process. It is passed dst, the lifted function, and the property name of + * the original function on src. + * @param {(object|function)?} dst option destination host onto which to place lifted + * functions. If not provided, liftAll returns a new object. + * @returns {*} If dst is provided, returns dst with lifted functions as + * properties. If dst not provided, returns a new object with lifted functions. + */ + function liftAll(src, combine, dst) { + return _liftAll(lift, combine, dst, src); + } + + /** + * Takes an object that responds to the resolver interface, and returns + * a function that will resolve or reject it depending on how it is called. + * + * @example + * function callbackTakingFunction(callback) { + * if(somethingWrongHappened) { + * callback(error); + * } else { + * callback(null, interestingValue); + * } + * } + * + * var when = require('when'), nodefn = require('when/node/function'); + * + * var deferred = when.defer(); + * callbackTakingFunction(nodefn.createCallback(deferred.resolver)); + * + * deferred.promise.then(function(interestingValue) { + * // Use interestingValue + * }); + * + * @param {Resolver} resolver that will be 'attached' to the callback + * @returns {Function} a node-style callback function + */ + function createCallback(resolver) { + return function(err, value) { + if(err) { + resolver.reject(err); + } else if(arguments.length > 2) { + resolver.resolve(slice.call(arguments, 1)); + } else { + resolver.resolve(value); + } + }; + } + + /** + * Attaches a node-style callback to a promise, ensuring the callback is + * called for either fulfillment or rejection. Returns a promise with the same + * state as the passed-in promise. + * + * @example + * var deferred = when.defer(); + * + * function callback(err, value) { + * // Handle err or use value + * } + * + * bindCallback(deferred.promise, callback); + * + * deferred.resolve('interesting value'); + * + * @param {Promise} promise The promise to be attached to. + * @param {Function} callback The node-style callback to attach. + * @returns {Promise} A promise with the same state as the passed-in promise. + */ + function bindCallback(promise, callback) { + promise = when(promise); + + if (callback) { + promise.then(success, wrapped); + } + + return promise; + + function success(value) { + wrapped(null, value); + } + + function wrapped(err, value) { + setTimer(function () { + callback(err, value); + }, 0); + } + } + + /** + * Takes a node-style callback and returns new function that accepts a + * promise, calling the original callback when the promise is either + * fulfilled or rejected with the appropriate arguments. + * + * @example + * var deferred = when.defer(); + * + * function callback(err, value) { + * // Handle err or use value + * } + * + * var wrapped = liftCallback(callback); + * + * // `wrapped` can now be passed around at will + * wrapped(deferred.promise); + * + * deferred.resolve('interesting value'); + * + * @param {Function} callback The node-style callback to wrap. + * @returns {Function} The lifted, promise-accepting function. + */ + function liftCallback(callback) { + return function(promise) { + return bindCallback(promise, callback); + }; + } +}); + +})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); + + + |