Skip to content

Commit

Permalink
Clean up and reformat in general. Add iterate and reduceRight tests. …
Browse files Browse the repository at this point in the history
…Slim array.js
  • Loading branch information
briancavalier committed Mar 14, 2014
1 parent 1bc4876 commit 480b8a8
Show file tree
Hide file tree
Showing 7 changed files with 307 additions and 219 deletions.
4 changes: 2 additions & 2 deletions callbacks.js
Expand Up @@ -58,15 +58,15 @@ define(function(require) {
* @returns {Promise} promise for the callback value of asyncFunction
*/
function apply(asyncFunction, extraAsyncArgs) {
return _apply(asyncFunction, this, extraAsyncArgs);
return _apply(asyncFunction, this, extraAsyncArgs || []);
}

/**
* Apply helper that allows specifying thisArg
* @private
*/
function _apply(asyncFunction, thisArg, extraAsyncArgs) {
return Promise.all(extraAsyncArgs || []).then(function(args) {
return Promise.all(extraAsyncArgs).then(function(args) {
var d = Promise._defer();
args.push(alwaysUnary(d.resolver.resolve, d.resolver),
alwaysUnary(d.resolver.reject, d.resolver));
Expand Down
26 changes: 16 additions & 10 deletions function.js
Expand Up @@ -30,14 +30,12 @@ define(function(require) {
* 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} func function to be called
* @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(func, promisedArgs) {
return arguments.length > 1
? attempt.apply(this, [func].concat(promisedArgs))
: attempt.call(this, func);
function apply(f, args) {
return _apply(f, this, args || []);
}

/**
Expand All @@ -48,19 +46,27 @@ define(function(require) {
*
* The resulting function is promise-aware, in the sense that it accepts
* promise arguments, and waits for their resolution.
* @param {Function} func function to be bound
* @param {Function} f function to be bound
* @param {...*} [args] arguments to be prepended for the new function
* @returns {Function} a promise-returning function
*/
function lift(func /*, args... */) {
function lift(f /*, args... */) {
var args = slice.call(arguments, 1);
return function() {
args.unshift(func);
args.push.apply(args, slice.call(arguments));
return attempt.apply(this, args);
return _apply(f, this, args.concat(slice.call(arguments)));
};
}

/**
* Apply helper that allows specifying thisArg
* @private
*/
function _apply(f, thisArg, args) {
return args.length === 0
? attempt.call(thisArg, f)
: attempt.apply(thisArg, [f].concat(args));
}

/**
* Lift all the functions/methods on src
* @param {object|function} src source whose functions will be lifted
Expand Down
60 changes: 13 additions & 47 deletions lib/array.js
Expand Up @@ -5,14 +5,13 @@
(function(define) { 'use strict';
define(function() {

var arrayMap = Array.prototype.map;
var arrayReduce = Array.prototype.reduce;
var arrayReduceRight = Array.prototype.reduceRight;
var arrayForEach = Array.prototype.forEach;
var arraySlice = Array.prototype.slice;

return function array(Promise) {

var arrayMap = Array.prototype.map;
var arrayReduce = Array.prototype.reduce;
var arrayReduceRight = Array.prototype.reduceRight;
var arrayForEach = Array.prototype.forEach;

var toPromise = Promise.resolve;
var all = Promise.all;

Expand Down Expand Up @@ -53,7 +52,7 @@ define(function() {
var pending = 0;
var errors = [];

runForEach(promises, function(p) {
arrayForEach.call(promises, function(p) {
++pending;
toPromise(p).then(resolve, handleReject);
});
Expand Down Expand Up @@ -88,7 +87,7 @@ define(function() {
var results = [];
var errors = [];

runForEach(promises, function(p) {
arrayForEach.call(promises, function(p) {
++nFulfill;
toPromise(p).then(handleResolve, handleReject, notify);
});
Expand Down Expand Up @@ -135,7 +134,7 @@ define(function() {
* @returns {Promise}
*/
function map(promises, f, fallback) {
return all(runMap(promises, function(x) {
return all(arrayMap.call(promises, function(x) {
return toPromise(x).then(f, fallback);
}));
}
Expand All @@ -148,7 +147,7 @@ define(function() {
* @returns {Promise}
*/
function settle(promises) {
return all(runMap(promises, function(p) {
return all(arrayMap.call(promises, function(p) {
p = toPromise(p);
return p.then(inspect, inspect);

Expand All @@ -160,8 +159,8 @@ define(function() {

function reduce(promises, f) {
return arguments.length > 2
? runReduce(promises, reducer, arguments[2])
: runReduce(promises, reducer);
? arrayReduce.call(promises, reducer, arguments[2])
: arrayReduce.call(promises, reducer);

function reducer(result, x, i) {
return toPromise(result).then(function(r) {
Expand All @@ -174,8 +173,8 @@ define(function() {

function reduceRight(promises, f) {
return arguments.length > 2
? runReduceRight(promises, reducer, arguments[2])
: runReduceRight(promises, reducer);
? arrayReduceRight.call(promises, reducer, arguments[2])
: arrayReduceRight.call(promises, reducer);

function reducer(result, x, i) {
return toPromise(result).then(function(r) {
Expand All @@ -187,39 +186,6 @@ define(function() {
}
};

function runForEach(x, f) {
if(x && typeof x.forEach === 'function') {
return x.forEach(f);
}

return arrayForEach.call(x, f);
}

function runMap(x, f) {
if(x && typeof x.map === 'function') {
return x.map(f);
}

return arrayMap.call(x, f);
}

function runReduce(x) {
var args = arraySlice.call(arguments, 1);
if(x && typeof x.reduce === 'function') {
return x.reduce.apply(x, args);
}

return arrayReduce.apply(x, args);
}

function runReduceRight(x) {
var args = arraySlice.call(arguments, 1);
if(x && typeof x.reduceRight === 'function') {
return x.reduceRight.apply(x, args);
}

return arrayReduceRight.apply(x, args);
}

});
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
26 changes: 17 additions & 9 deletions lib/makePromise.js
Expand Up @@ -168,8 +168,8 @@ define(function() {
for (i = 0; i < len; ++i) {
if (i in promises) {
x = promises[i];
if (typeof x === 'object' || typeof x === 'function') {
resolveOne(resolver, results, getHandler(x), i);
if (maybeThenable(x)) {
resolveOne(resolver, results, getHandlerChecked(x), i);
} else {
results[i] = x;
--pending;
Expand Down Expand Up @@ -249,17 +249,17 @@ define(function() {
*/
function getHandler(x, h) {
if(x instanceof Promise) {
return getHandlerChecked(x, h);
return getHandlerPromise(x, h);
}

if(Object(x) === x) {
return getHandlerUntrusted(x);
}

return new FulfilledHandler(x);
return maybeThenable(x) ? getHandlerUntrusted(x) : new FulfilledHandler(x);
}

function getHandlerChecked(x, h) {
return x instanceof Promise
? getHandlerPromise(x, h) : getHandlerUntrusted(x);
}

function getHandlerPromise(x, h) {
var h2 = x._handler.join();
return h === h2 ? promiseCycleError : h2;
}
Expand Down Expand Up @@ -623,6 +623,14 @@ define(function() {
notify.call(t, x);
};

/**
* @param {*} x
* @returns {boolean} false iff x is guaranteed not to be a thenable
*/
function maybeThenable(x) {
return (typeof x === 'object' || typeof x === 'function') && x !== null;
}

/**
* Return f.call(thisArg, x), or if it throws return a rejected promise for
* the thrown exception
Expand Down
18 changes: 13 additions & 5 deletions node.js
Expand Up @@ -69,14 +69,22 @@ define(function(require) {
*/
function _apply(func, thisArg, args) {
return Promise.all(args).then(function(args) {
var d = Promise._defer();
args.push(createCallback(d.resolver));
func.apply(thisArg, args);

return d.promise;
return _applyDirect(func, thisArg, args);
});
}

/**
* Apply helper that optimizes for small number of arguments
* @private
*/
function _applyDirect(func, thisArg, args) {
var d = Promise._defer();
var cb = createCallback(d.resolver);
args.push(cb);
func.apply(thisArg, args);
return d.promise;
}

/**
* Has the same behavior that {@link apply} has, with the difference that the
* arguments to the function are provided individually, while {@link apply} accepts
Expand Down
28 changes: 27 additions & 1 deletion test/iterate-test.js
Expand Up @@ -198,8 +198,34 @@ define('when/iterate-test', function (require) {
},

'iterate': {
'//should invoke condition first': function() {
'should invoke condition first': function() {
var called = false;

return when.iterate(function(x) {
assert(called);
return x;
}, function() {
refute(called);
called = true;
return true;
}, function(x) {
assert(called);
return x;
}, 0).then(function() {
assert(called);
});
},

'should return a promise for ultimate result': function() {
return when.iterate(function(x) {
return x+1;
}, function(x) {
return x >= 10;
}, function(x) {
return x;
}, 0).then(function(x) {
assert.equals(x, 10);
});
}
}
});
Expand Down

0 comments on commit 480b8a8

Please sign in to comment.