Skip to content

Instantly share code, notes, and snippets.

@RSNara
Last active December 30, 2015 06:04
Show Gist options
  • Save RSNara/900ad5567c2a66f7c7d4 to your computer and use it in GitHub Desktop.
Save RSNara/900ad5567c2a66f7c7d4 to your computer and use it in GitHub Desktop.
Promise.tree
/**
* A Tree is an Object that may contain other Trees, Objects, Promises,
* or primitives. By definition, it contains no cycles.
* @typedef [Object] Tree
*/
/**
* @function tree
* @memberof Promise
* @param [Tree] tree
* @returns [Promise] - A Tree with all promises resolved.
*
* @description
* Works like $q.all, but for arbitrarily nested objects.
*
* @example
* ```javascript
* const tree = {
* one: Promise.resolve(1),
* two: {
* three: 'three',
* four: Promise.resolve(4),
* },
* five: 5,
* };
*
* Promise.tree(tree).then((result) => {
* assert.deepEqual(result, {
* one: 1,
* two: {
* three: 'three',
* four: 4,
* },
* five: 5,
* });
* });
* ```
*/
const isObject = (x) => Object(x) === x;
const isTree = (x) => isObject(x) && ! (typeof x.then === 'function');
const transform = (x) => isTree(x) ? Promise.tree(x) : x;
const keys = (x) => Object.keys(x);
const objectKeyReduce = (fn, init, x) => keys(x).reduce(fn, init);
const merge = (...args) => Object.assign({}, ...args);
function zip(names) {
return (values) => names.reduce(
(map, name, index) => merge(map, {
[name]: values[index],
}), {}
);
}
Promise.tree = (tree) => (
Promise.all(
objectKeyReduce(
(promises, key) => (
[...promises, transform(tree[key])]
), [], tree
)
).then(
zip(keys(tree))
)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment