UNPKG

4.03 kBJavaScriptView Raw
1/** @license MIT License (c) copyright 2013-2014 original author or authors */
2
3/**
4 * Collection of helper functions for wrapping and executing 'traditional'
5 * synchronous functions in a promise interface.
6 *
7 * @author Brian Cavalier
8 * @contributor Renato Zannon
9 */
10
11(function(define) {
12define(function(require) {
13
14 var when = require('./when');
15 var attempt = when['try'];
16 var _liftAll = require('./lib/liftAll');
17 var slice = Array.prototype.slice;
18
19 return {
20 lift: lift,
21 liftAll: liftAll,
22 call: attempt,
23 apply: apply,
24 compose: compose
25 };
26
27 /**
28 * Takes a function and an optional array of arguments (that might be promises),
29 * and calls the function. The return value is a promise whose resolution
30 * depends on the value returned by the function.
31 * @param {function} f function to be called
32 * @param {Array} [args] array of arguments to func
33 * @returns {Promise} promise for the return value of func
34 */
35 function apply(f, args) {
36 // slice args just in case the caller passed an Arguments instance
37 return _apply(f, this, args == null ? [] : slice.call(args));
38 }
39
40 /**
41 * Takes a 'regular' function and returns a version of that function that
42 * returns a promise instead of a plain value, and handles thrown errors by
43 * returning a rejected promise. Also accepts a list of arguments to be
44 * prepended to the new function, as does Function.prototype.bind.
45 *
46 * The resulting function is promise-aware, in the sense that it accepts
47 * promise arguments, and waits for their resolution.
48 * @param {Function} f function to be bound
49 * @param {...*} [args] arguments to be prepended for the new function @deprecated
50 * @returns {Function} a promise-returning function
51 */
52 function lift(f /*, args... */) {
53 var args = arguments.length > 1 ? slice.call(arguments, 1) : [];
54 return function() {
55 return _apply(f, this, args.concat(slice.call(arguments)));
56 };
57 }
58
59 /**
60 * Apply helper that allows specifying thisArg
61 * @private
62 */
63 function _apply(f, thisArg, args) {
64 // args MUST be an Array
65 return args.length === 0
66 ? attempt.call(thisArg, f)
67 : attempt.apply(thisArg, [f].concat(args));
68 }
69
70 /**
71 * Lift all the functions/methods on src
72 * @param {object|function} src source whose functions will be lifted
73 * @param {function?} combine optional function for customizing the lifting
74 * process. It is passed dst, the lifted function, and the property name of
75 * the original function on src.
76 * @param {(object|function)?} dst option destination host onto which to place lifted
77 * functions. If not provided, liftAll returns a new object.
78 * @returns {*} If dst is provided, returns dst with lifted functions as
79 * properties. If dst not provided, returns a new object with lifted functions.
80 */
81 function liftAll(src, combine, dst) {
82 return _liftAll(lift, combine, dst, src);
83 }
84
85 /**
86 * Composes multiple functions by piping their return values. It is
87 * transparent to whether the functions return 'regular' values or promises:
88 * the piped argument is always a resolved value. If one of the functions
89 * throws or returns a rejected promise, the composed promise will be also
90 * rejected.
91 *
92 * The arguments (or promises to arguments) given to the returned function (if
93 * any), are passed directly to the first function on the 'pipeline'.
94 * @param {Function} f the function to which the arguments will be passed
95 * @param {...Function} [funcs] functions that will be composed, in order
96 * @returns {Function} a promise-returning composition of the functions
97 */
98 function compose(f /*, funcs... */) {
99 var funcs = slice.call(arguments, 1);
100
101 return function() {
102 var thisArg = this;
103 var args = slice.call(arguments);
104 var firstPromise = attempt.apply(thisArg, [f].concat(args));
105
106 return when.reduce(funcs, function(arg, func) {
107 return func.call(thisArg, arg);
108 }, firstPromise);
109 };
110 }
111});
112})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
113
114