Skip to content

Instantly share code, notes, and snippets.

@loretoparisi
Last active February 5, 2020 20:33
Show Gist options
  • Save loretoparisi/a4b016913b17730f82a0af3fb20ba32d to your computer and use it in GitHub Desktop.
Save loretoparisi/a4b016913b17730f82a0af3fb20ba32d to your computer and use it in GitHub Desktop.
JavaScript Sequence of Promise
/**
* @param {Object} obj
* @return true if obj is Promise
*/
function isPromise(obj) {
return obj && typeof obj.then === 'function';
}
/**
* Waterfall of Promises
* @param list Array Array of Promises
* @author: adpated by Loreto Parisi based on original code with missing references
* please claim back this code if you know the author!
* @return Promise
*/
function waterfall(list) {
// malformed argument
list = Array.prototype.slice.call(list);
if (!Array.isArray(list) // not an array
|| typeof list.reduce !== "function" // update your javascript engine
|| list.length < 1 // empty array
) {
return Promise.reject("Array with reduce function is needed.");
}
if (list.length == 1) {
if (typeof list[0] != "function")
return Promise.reject("First element of the array should be a function, got " + typeof list[0]);
return Promise.resolve(list[0]());
}
return list.reduce(function (l, r) {
// first round
// execute function and return promise
var isFirst = (l == list[0]);
if (isFirst) {
if (typeof l != "function")
return Promise.reject("List elements should be function to call.");
var lret = l();
if (!isPromise(lret))
return Promise.reject("Function return value should be a promise.");
else
return lret.then(r);
}
// other rounds
// l is a promise now
// priviousPromiseList.then(nextFunction)
else {
if (!isPromise(l))
Promise.reject("Function return value should be a promise.");
else
return l.then(r);
}
});
}
/**
* Iterate over a sequence of promises
* @param data Array Array of input
* @param callback function Callback: input data returns Promise
* @return Promise
*/
function sequence(data, callback) {
var copycat = [].concat(data);//clone array
var first = copycat.splice(0, 1)[0];//remove first
var promises = [() => callback.apply(this, [first,0])]
.concat(copycat.map((item,index) => (res) => callback.apply(this, [item,index+1])));
return waterfall(promises);
}
@loretoparisi
Copy link
Author

loretoparisi commented Feb 5, 2020

Usage:

Supposed to have a sleep Promise:

function sleep(milliseconds) {
    return new Promise(resolve => setTimeout(resolve, milliseconds))
}

if you want to perform a sequence of sleep before running your code:

sequence(items, (item, index) => {
        return new Promise((next, _) => {
            sleep(500).then(() => {
                // do something with `item` after sleeping...
                return next(item);
            })
        })
    })
    .then(res => {
        return resolve(res);
    })
    .catch(error => {
        return reject(error);
    });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment