blob: b76172b073be382bbc4915b4c7f0e0f6be2a3371 [file] [log] [blame]
/** @license MIT License (c) copyright 2013-2014 original author or authors */
/**
* Collection of helper functions for wrapping and executing 'traditional'
* synchronous functions in a promise interface.
*
* @author Brian Cavalier
* @contributor Renato Zannon
*/
(function(define) {
define(function(require) {
var when = require('./when');
var attempt = when['try'];
var _liftAll = require('./lib/liftAll');
var _apply = require('./lib/apply')(when.Promise);
var slice = Array.prototype.slice;
return {
lift: lift,
liftAll: liftAll,
call: attempt,
apply: apply,
compose: compose
};
/**
* Takes a function and an optional array of arguments (that might be promises),
* and calls the function. The return value is a promise whose resolution
* depends on the value returned by the function.
* @param {function} f function to be called
* @param {Array} [args] array of arguments to func
* @returns {Promise} promise for the return value of func
*/
function apply(f, args) {
// slice args just in case the caller passed an Arguments instance
return _apply(f, this, args == null ? [] : slice.call(args));
}
/**
* Takes a 'regular' function and returns a version of that function that
* returns a promise instead of a plain value, and handles thrown errors by
* returning a rejected promise. Also accepts a list of arguments to be
* prepended to the new function, as does Function.prototype.bind.
*
* The resulting function is promise-aware, in the sense that it accepts
* promise arguments, and waits for their resolution.
* @param {Function} f function to be bound
* @param {...*} [args] arguments to be prepended for the new function @deprecated
* @returns {Function} a promise-returning function
*/
function lift(f /*, args... */) {
var args = arguments.length > 1 ? slice.call(arguments, 1) : [];
return function() {
return _apply(f, this, args.concat(slice.call(arguments)));
};
}
/**
* 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);
}
/**
* Composes multiple functions by piping their return values. It is
* transparent to whether the functions return 'regular' values or promises:
* the piped argument is always a resolved value. If one of the functions
* throws or returns a rejected promise, the composed promise will be also
* rejected.
*
* The arguments (or promises to arguments) given to the returned function (if
* any), are passed directly to the first function on the 'pipeline'.
* @param {Function} f the function to which the arguments will be passed
* @param {...Function} [funcs] functions that will be composed, in order
* @returns {Function} a promise-returning composition of the functions
*/
function compose(f /*, funcs... */) {
var funcs = slice.call(arguments, 1);
return function() {
var thisArg = this;
var args = slice.call(arguments);
var firstPromise = attempt.apply(thisArg, [f].concat(args));
return when.reduce(funcs, function(arg, func) {
return func.call(thisArg, arg);
}, firstPromise);
};
}
});
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });