Promise-utils

Collection of promise utilities

View project onGitHub

Build Status

browser support

promise-utils

promise-utils is a Javascript library that provides utilities for working with promises. promise-utils can be used as a monad library for promises or each function can be used standalone.

This library uses promise-extended internally but can be used with any promises A+ compliant library such as Q

promise-utils can be used standalone or incorporated into extended

var pUtils = require("promise-utils");

Or

var myextended = require("extended")
    .register(require("promise-extended"));

Installation

npm install promise-utils

Or download the source (minified)

Usage

Arrays

promise-utils can be used with promises or normal arrays by using the async method.

NOTE The examples below uses a resolve method which represents turning an array into a promise resolved with the given array. This is used for brevity where you would typically be working with promises returned from an asynchronous method such as a database call.

var arr = [1,2,3];
var promiseArr = resolve(arr);

pUtils(arr).async().forEach(function(item){
    console.log(item);
}).then(function(){
    console.log("Done Looping");
});

//OR

pUtils(promiseArr).forEach(function(item){
    console.log(item);
}).then(function(){
    console.log("Done Looping");
});


Chaining

When using promise-utils as a monad with a promise you may chain methods together.

var arr = resolve([1, 2, 3, 4, 5]);
pUtils(arr)
    .map(function (num, i) {
        return num * (i + 1);
    })
    .filter(function (num) {
        return num % 2;
    })
    .avg()
    .then(function(res){
        //11.666666666666666
    });

forEach

Similar to Array#forEach except that it resolves with the original array for chaining.

//as a monad

pUtils(resolve([1, 2, 3])).forEach(function(item){
    console.log(item);
}).then(function(){
    console.log("Done Looping");
});

pUtils.forEach(resolve([1, 2, 3]), function(item){
    console.log(item);
}).then(function(){
    console.log("Done Looping");
});

You may also return a promise from the iterator function, which will prevent the returned promise from resolving until all the returned promises are done.

pUtils(resolve([1, 2, 3])).forEach(function(item){
     var ret = new Promise();
     setTimeout(function(){
        ret.callback(item);
     }, 200);
     return ret.promise();
}).then(function(){
    //all promises from iterator function are resolved.
    console.log("Done Looping");
});

You may also specify a limit which will specify the number of items to be looped at a time, if limit is not specified then all items will be iterated regardless of whether or not the previous item in the array is done.

pUtils(resolve([1, 2, 3])).forEach(function(item){
    var ret = new Promise();
    setTimeout(function(){
        ret.callback(item);
    }, 200);
    return ret.promise();
}, 1).then(function(){
    console.log("Done Looping");
});

In the above example only one item will be iterated one at a time.

map

Async version of Array#map.

//as a monad

pUtils(resolve([1, 2, 3])).map(function(item){
    return item * 2;
}).then(function(result){
    console.log(result); //[2, 4, 6];
});

pUtils.map(resolve([1, 2, 3]), function(item){
    return item * 2;
}).then(function(result){
    console.log(result); //[2, 4, 6];
});

You may also return a promise from the iterator function, which will prevent the returned promise from resolving until all the returned promises are done.

 //as a monad

pUtils(resolve([1, 2, 3])).map(function(item){
     var ret = new Promise();
     setTimeout(function(){
        ret.callback(item * 2);
     }, 200);
     return ret.promise();
}).then(function(result){
    console.log(result); //[2, 4, 6];
});

You may also specify a limit which will specify the number of items to be looped at a time, if limit is not specified then all items will be iterated regardless of whether or not the previous item in the array is done.

pUtils(resolve([1, 2, 3])).map(function(item){
    var ret = new Promise();
    setTimeout(function(){
        ret.callback(item * 2);
    }, 200);
    return ret.promise();
}, 1).then(function(){
    console.log(result); //[2, 4, 6];
});

In the above example only one item will be iterated at a time.

filter

Async version of Array#filter.

//as a monad

pUtils(resolve([1, 2, 3])).filter(function(item){
    return item % 2;
}).then(function(result){
    console.log(result); //[1, 3];
});

pUtils.filter(resolve([1, 2, 3]), function(item){
    return item % 2;
}).then(function(result){
    console.log(result); //[1, 3];
});

You may also return a promise from the iterator function, which will prevent the returned promise from resolving until all the returned promises are done.

 //as a monad

pUtils(resolve([1, 2, 3])).filter(function(item){
     var ret = new Promise();
     setTimeout(function(){
        ret.callback(item % 2);
     }, 200);
     return ret.promise();
}).then(function(result){
    console.log(result); //[1, 3];
});

You may also specify a limit which will specify the number of items to be looped at a time, if limit is not specified then all items will be iterated regardless of whether or not the previous item in the array is done.

pUtils(resolve([1, 2, 3])).filter(function(item){
    var ret = new Promise();
    setTimeout(function(){
        ret.callback(item % 2);
    }, 200);
    return ret.promise();
}, 1).then(function(){
    console.log(result); //[1, 3];
});

In the above example only one item will be iterated at a time.

every

Async version of Array#every.

pUtils(resolve([1, 2, 3])).every(function(item){
    return isNumber(item);
}).then(function(result){
    console.log(result); //true;
});

pUtils.every(resolve([1, 2, 3]), function(item){
    return isNumber(item);
}).then(function(result){
    console.log(result); //true;
});

You may also return a promise from the iterator function, which will prevent the returned promise from resolving until all the returned promises are done.

 //as a monad

pUtils(resolve([1, 2, 3])).every(function(item){
     var ret = new Promise();
     setTimeout(function(){
        ret.callback(isNumber(item));
     }, 200);
     return ret.promise();
}).then(function(result){
    console.log(result); //[true];
});

You may also specify a limit which will specify the number of items to be looped at a time, if limit is not specified then all items will be iterated regardless of whether or not the previous item in the array is done.

pUtils(resolve([1, 2, 3])).every(function(item){
    var ret = new Promise();
    setTimeout(function(){
        ret.callback(isNumber(item));
    }, 200);
    return ret.promise();
}, 1).then(function(){
    console.log(result); //true;
});

In the above example only one item will be iterated at a time.

some

Async version of Array#every.

pUtils(resolve([1, 2, 3])).some(function(item){
    return item === 1;
}).then(function(result){
    console.log(result); //true;
});

pUtils.some(resolve([1, 2, 3]), function(item){
    return item === 1;
}).then(function(result){
    console.log(result); //true;
});

You may also return a promise from the iterator function, which will prevent the returned promise from resolving until all the returned promises are done.

 //as a monad

pUtils(resolve([1, 2, 3])).some(function(item){
     var ret = new Promise();
     setTimeout(function(){
        ret.callback(item === 1);
     }, 200);
     return ret.promise();
}).then(function(result){
    console.log(result); //[true];
});

You may also specify a limit which will specify the number of items to be looped at a time, if limit is not specified then all items will be iterated regardless of whether or not the previous item in the array is done.

pUtils(resolve([1, 2, 3])).some(function(item){
    var ret = new Promise();
    setTimeout(function(){
        ret.callback(item === 1);
    }, 200);
    return ret.promise();
}, 1).then(function(){
    console.log(result); //true;
});

In the above example only one item will be iterated at a time.

sum

Sums the values of an array

pUtils.sum(resolve([1,2,3])).then(function(sum){
   //6
});

pUtils(resolve([1,2,3])).sum().then(function(sum){
    //6
});

avg

Finds the average of an array of numbers.

pUtils.avg(resolve([1,2,3])).then(function(avg){
    //2
});

pUtils(resolve([1,2,3])).avg().then(function(avg){
    //2
});

sort

Sorts an array based on a property, by natural ordering, or by a custom comparator.

Note this does not change the original array.

pUtils.sort(resolve([{a: 1},{a: 2},{a: -2}]), "a").then(function(sorted){
    //[{a: -2},{a: 1},{a: 2}];
})

pUtils(resolve([{a: 1},{a: 2},{a: -2}])).sort("a").then(function(sorted){
    //[{a: -2},{a: 1},{a: 2}];
})


min

Finds the minimum value in an array based on a property, by natural ordering, or by a custom comparator.

pUtils.min(resolve([ 3, -3, -2, -1, 1, 2])).then(function(min){
    //-3
});

pUtils.min(resolve([{a: 1},{a: 2},{a: -2}]), "a").then(function(min){
    //{a : -2}
});

pUtils(resolve([ 3, -3, -2, -1, 1, 2])).min().then(function(min){
    //-3
});

pUtils(resolve([{a: 1},{a: 2},{a: -2}])).min("a").then(function(min){
    //{a : -2}
});

max

Finds the maximum value in an array based on a property, by natural ordering, or by a custom comparator.

pUtils.max(resolve([ 3, -3, -2, -1, 1, 2])).then(function(max){
     //2
});

pUtils.max(resolve([{a: 1},{a: 2},{a: -2}]), "a").then(function(max){
    //{a : 2}
});

pUtils(resolve([ 3, -3, -2, -1, 1, 2])).max().then(function(max){
    //2
});

pUtils(resolve([{a: 1},{a: 2},{a: -2}])).max("a").then(function(max){
    //{a : 2}
});

difference

Finds the difference between two arrays.

pUtils.difference(resolve([1, 2, 3]), [2]).then(function(diff){
    //[1, 3]
});
pUtils.difference(resolve([true, false]), resolve([false])).then(function(diff){
    //[true]
});

pUtils.difference(resolve(["a", "b", 3]), resolve([3])).then(function(diff){
    //["a", "b"]
});

pUtils.difference(resolve([{a: 1}, {a: 2}, {a: 3}]), resolve([{a: 2}, {a: 3}])).then(function(diff){
    //[{a: 1}]
});

pUtils(resolve([true, false])).difference([false]).then(function(diff){
    // [true]
});

pUtils(resolve([1, 2, 3])).difference(resolve([2])).then(function(diff){
    // [1, 3]
});
pUtils(resolve([1, 2, 3])).difference([2], resolve([3])).then(function(diff){
     //[1]
});

pUtils(resolve(["a", "b", 3])).difference([3]).then(function(diff){
     //["a", "b"]
});
pUtils(resolve([{a: 1}, {a: 2}, {a: 3}])).difference(resolve([{a: 2}, {a: 3}])).then(function(diff){
    // [{a: 1}]
});

unique

Removed duplicate values from an array

pUtils.unique(resolve([1, 2, 2, 3, 3, 3, 4, 4, 4])).then(function(unique){
    //[1, 2, 3, 4]
}):
pUtils(resolve([1, 2, 2, 3, 3, 3, 4, 4, 4])).unique().then(function(unique){
    //[1, 2, 3, 4]
});

pUtils(resolve(["a", "b", "b"])).unique().then(function(unique){
    //["a", "b"]
});

pUtils.unique(resolve(["a", "b", "b"])).then(function(unique){
    //["a", "b"]
});

rotate

Rotates an array by the number of places for 1 position by default.

var arr = pUtils(resolve(["a", "b", "c", "d"]))
arr.rotate();   //resolves with ["b", "c", "d", "a"]
arr.rotate(2);  //resolves with ["c", "d", "a", "b"]
arr.rotate(3);  //resolves with ["d", "a", "b", "c"]
arr.rotate(4);  //resolves with ["a", "b", "c", "d"]
arr.rotate(-1); //resolves with ["d", "a", "b", "c"]
arr.rotate(-2); //resolves with ["c", "d", "a", "b"]
arr.rotate(-3); //resolves with ["b", "c", "d", "a"]
arr.rotate(-4); //resolves with ["a", "b", "c", "d"]

arr = resolve(["a", "b", "c", "d"]);
pUtils.rotate(arr);     //resolves with ["b", "c", "d", "a"]
pUtils.rotate(arr, 2);  //resolves with ["c", "d", "a", "b"]
pUtils.rotate(arr, 3);  //resolves with ["d", "a", "b", "c"]
pUtils.rotate(arr, 4);  //resolves with ["a", "b", "c", "d"]
pUtils.rotate(arr, -1)  //resolves with ["d", "a", "b", "c"]
pUtils.rotate(arr, -2); //resolves with ["c", "d", "a", "b"]
pUtils.rotate(arr, -3); //resolves with ["b", "c", "d", "a"]
pUtils.rotate(arr, -4); //resolves with ["a", "b", "c", "d"]

permutations

Finds all permutations of an array.

pUtils(resolve([1, 2, 3])).permutations(); //resolves with [
                                 //   [ 1, 2, 3 ],
                                 //   [ 1, 3, 2 ],
                                 //   [ 2, 3, 1 ],
                                 //   [ 2, 1, 3 ],
                                 //   [ 3, 1, 2 ],
                                 //   [ 3, 2, 1 ]
                                 //]

pUtils(resolve([1, 2, 3])).permutations(2);// resolves with [
                                           //   [ 1, 2],
                                           //   [ 1, 3],
                                           //   [ 2, 3],
                                           //   [ 2, 1],
                                           //   [ 3, 1],
                                           //   [ 3, 2]
                                           //]

pUtils.permutations(resolve([1, 2, 3]));   // resolves with [
                                 //   [ 1, 2, 3 ],
                                 //   [ 1, 3, 2 ],
                                 //   [ 2, 3, 1 ],
                                 //   [ 2, 1, 3 ],
                                 //   [ 3, 1, 2 ],
                                 //   [ 3, 2, 1 ]
                                 //]

pUtils.permutations(resolve([1, 2, 3]), 2); //resolves with [
                                    //   [ 1, 2],
                                    //   [ 1, 3],
                                    //   [ 2, 3],
                                    //   [ 2, 1],
                                    //   [ 3, 1],
                                    //   [ 3, 2]
                                    //]

zip

Zips the values of multiple arrays into a single pUtils.

pUtils(resolve([1])).zip(resolve([2]), resolve([3]));//resolves with [
                                                     //  [ 1, 2, 3 ]
                                                     //];

pUtils(resolve([1, 2])).zip(resolve([2]), [3]);      //resolves with [
                                                     //  [ 1, 2, 3 ],
                                                     //  [2, null, null]
                                                     //]

pUtils(resolve([1, 2, 3])).zip([ 4, 5, 6 ], b);      //resolves with [
                                                     //  [1, 4, 7],
                                                     //  [2, 5, 8],
                                                     //  [3, 6, 9]
                                                     //]

pUtils(resolve([1, 2])).zip([ 4, 5, 6 ], resolve([7, 8, 9 ])); //resolves with [
                                                               //  [1, 4, 7],
                                                               //  [2, 5, 8]
                                                               //]

pUtils(resolve([ 4, 5, 6 ])).zip([1, 2], [8]);       //resolves with [
                                                     //  [4, 1, 8],
                                                     //  [5, 2, null],
                                                     //  [6, null, null]
                                                     //]


pUtils.zip(resolve([1]), [2], [3]);                  //resolves with [
                                                     //  [ 1, 2, 3 ]
                                                     //]

pUtils.zip(resolve([1, 2]), resolve([2]), [3]);      //resolves with [
                                                     //  [ 1, 2, 3 ],
                                                     //  [2, null, null]
                                                     //]

pUtils.zip(resolve([1, 2, 3]), [4,5,6],  resolve([7, 8, 9 ])); //resolves with [
                                                               //  [1, 4, 7],
                                                               //  [2, 5, 8],
                                                               //  [3, 6, 9]
                                                               //]

pUtils.zip(resolve([1, 2]), [4,5,6],  [7, 8, 9 ]);    //resolves with [
                                                      //  [1, 4, 7],
                                                      //  [2, 5, 8]
                                                      //]

pUtils.zip([ 4, 5, 6 ], [1, 2], resolve([8]));        //resolves with [
                                                      //  [4, 1, 8],
                                                      //  [5, 2, null],
                                                      //  [6, null, null]
                                                      //]

transpose

Transpose a multi dimensional array.

pUtils(resolve([[1, 2, 3],[4, 5, 6]])).transpose();   //resolves with [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ]
pUtils([[1, 2],[3, 4],[5, 6]]).async().transpose();   //resolves with [ [ 1, 3, 5 ], [ 2, 4, 6 ] ]
pUtils(resolve([[1],[3, 4],[5, 6]])).transpose();     //resolves with [ [1] ]


pUtils.transpose(resolve([[1, 2, 3],[4, 5, 6]]));     //resolves with [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ]
pUtils.transpose(resolve([[1, 2],[3, 4],[5, 6]]));    //resolves with [ [ 1, 3, 5 ], [ 2, 4, 6 ] ]
pUtils.transpose(resolve([[1],[3, 4],[5, 6]]));       //resolves with [ [1] ]

valuesAt

Gathers values at the specified indexes.

var arr = pUtils(resolve(["a", "b", "c", "d"]));
arr.valuesAt(1, 2, 3);      //resolves with ["b", "c", "d"]
arr.valuesAt(1, 2, 3, 4);   //resolves with ["b", "c", "d", null]
arr.valuesAt(0, 3);         //resolves with ["a", "d"]

arr = resolve(["a", "b", "c", "d"]);
pUtils.valuesAt(arr, 1, 2, 3);       //resolves with ["b", "c", "d"]
pUtils.valuesAt(arr, 1, 2, 3, 4);    //resolves with ["b", "c", "d", null]
pUtils.valuesAt(arr, 0, 3);          //resolves with ["a", "d"]

union

Finds the union of two arrays.

pUtils(resolve(["a", "b", "c"])).union(["b", "c", "d"]);           //resolves with ["a", "b", "c", "d"]);
pUtils(["a"]).async().union(["b"], ["c"], ["d"], resolve(["c"]));  //resolves with ["a", "b", "c", "d"]);

pUtils.union(resolve(["a", "b", "c"]), ["b", "c", "d"]);           //resolves with ["a", "b", "c", "d"]);
pUtils.union(resolve(["a"]), ["b"], resolve(["c"]), ["d"], ["c"]); //resolves with ["a", "b", "c", "d"]);

intersect

Finds the intersection of arrays.

pUtils(resolve([1, 2])).intersect([2, 3], [2, 3, 5]);                            //resolves with [2];
pUtils(resolve([1, 2, 3])).intersect([2, 3, 4, 5], [2, 3, 5]);                   //resolves with [2, 3];
pUtils(resolve([1, 2, 3, 4])).intersect([2, 3, 4, 5], [2, 3, 4, 5]);             //resolves with [2, 3, 4];
pUtils(resolve([1, 2, 3, 4, 5])).intersect([1, 2, 3, 4, 5], [1, 2, 3]);          //resolves with [1, 2, 3];
pUtils(resolve([[1, 2, 3, 4, 5],[1, 2, 3, 4, 5],[1, 2, 3]])).intersect();        //resolves with [1, 2, 3];

pUtils.intersect(resolve([1, 2]), [2, 3], [2, 3, 5]);                             //resolves with [2]
pUtils.intersect(resolve([1, 2, 3]), [2, 3, 4, 5], [2, 3, 5]);                    //resolves with [2, 3]
pUtils.intersect(resolve([1, 2, 3, 4]), [2, 3, 4, 5], resolve([2, 3, 4, 5]));     //resolves with [2, 3, 4]
pUtils.intersect(resolve([1, 2, 3, 4, 5]), [1, 2, 3, 4, 5], [1, 2, 3]);           //resolves with [1, 2, 3]);
pUtils.intersect(resolve([[1, 2, 3, 4, 5],[1, 2, 3, 4, 5], [1, 2, 3]]));          //resolves with [1, 2, 3]);

powerSet

Finds the powerset of a given array.

pUtils(resolve([1, 2, 3])).powerSet();
pUtils.powerSet(resolve([1, 2, 3]));
//Both resolve with
//[
//  [],
//  [ 1 ],
//  [ 2 ],
//  [ 1, 2 ],
//  [ 3 ],
//  [ 1, 3 ],
//  [ 2, 3 ],
//  [ 1, 2, 3 ]
//]

cartesian

Finds the cartesian product of arrays.

pUtils(resolve([1, 2])).cartesian(resolve([2, 3]));
pUtils.cartesian(resolve([1, 2]), [2, 3]);
//Both resolve with
//[
//  [1, 2],
//  [1, 3],
//  [2, 2],
//  [2, 3]
//]

compact

Compacts the values of an array.

pUtils(resolve([1, null, null, x, 2])).compact(); //Resolves with [1, 2]

pUtils([1, 2]).async().compact();  //Resolves with [1, 2]


pUtils.compact(resolve([1, null, null, x, 2])); //Resolves with [1, 2]
pUtils.compact(resolve([1, 2])); //Resolves with [1, 2]

multiply

Reproduces the values in an array the given number of times.

pUtils(resolve([1, 2])).multiply(2); //Resolves with[1, 2, 1, 2, 1, 2]

pUtils.multiply(resolve([1, 2, 3]), 2); //Resolves with [1, 2, 3, 1, 2, 3]

flatten

Flatten multiple arrays into a single array.

pUtils(resolve([ [1], [2], [3] ])).flatten(); //Resolves with [1, 2, 3]

pUtils.flatten(resolve([1, 2]), [2, 3], resolve([3, 4])); //Resolves with [1, 2, 2, 3, 3, 4]

pluck

Pluck properties from values in an array.

NOTE Plucked properties may also be promises. pluck will return the resolved value of the promise

var arr = resolve([
    {name: {first: "Fred", last: "Jones"}, age: 50, roles: ["a", "b", "c"]},
    {name: {first: resolve("Bob"), last: "Yukon"}, age: resolve(40), roles: resolve(["b", "c"])},
    {name: {first: "Alice", last: "Palace"}, age: 35, roles: ["c"]},
    {name: {first: resolve("Johnny"), last: "P."}, age: 56, roles: resolve([])}
]);

pUtils.pluck(arr, "name.first"); //Resolves with ["Fred", "Bob", "Alice", "Johnny"]
pUtils(arr).pluck("age"); //Resolves with [50, 40, 35, 56]

invoke

Invokes the specified method on each value in an array.

function person(name, age) {
    return {
        getName: function () {
            return resolve(name);
        },

        getOlder: function () {
            age++;
            return resolve(this);
        },

        getAge: function () {
            return resolve(age);
        }
    };
};

var arr = resolve([person("Bob", 40), person("Alice", 35), person("Fred", 50), person("Johnny", 56)]);

pUtils.invoke(arr, "getName"); //Resolves with ["Bob", "Alice", "Fred", "Johnny"];
pUtils(arr).invoke("getName"); //Resolves with ["Bob", "Alice", "Fred", "Johnny"];

pUtils(arr).invoke("getOlder").invoke("getAge"); //Resolves with [41, 36, 51, 57];