-
-
Save developit/7a6e48654b88002a835f8f6bc4535a6d to your computer and use it in GitHub Desktop.
/** Async version of Array.prototype.reduce() | |
* await reduce(['/foo', '/bar', '/baz'], async (acc, v) => { | |
* acc[v] = await (await fetch(v)).json(); | |
* return acc; | |
* }, {}); | |
*/ | |
export async function reduce(arr, fn, val, pure) { | |
for (let i=0; i<arr.length; i++) { | |
let v = await fn(val, arr[i], i, arr); | |
if (pure!==false) val = v; | |
} | |
return val; | |
} | |
/** Async version of Array.prototype.map() | |
* await map(['foo', 'baz'], async v => await fetch(v) ) | |
*/ | |
export async function map(arr, fn) { | |
return await reduce(arr, (acc, value, index, arr) => { | |
acc.push(await fn(value, index, arr)); | |
}, [], false); | |
} | |
/** Async version of Array.prototype.filter() | |
* await filter(['foo', 'baz'], async v => (await fetch(v)).ok ) | |
*/ | |
export async function filter(arr, fn) { | |
return await reduce(arr, (acc, value, index, arr) => { | |
if (await fn(value, index, arr)) acc.push(value); | |
}, [], false); | |
} | |
function identity(x) { | |
return x; | |
} | |
function resolve(list) { | |
let out = Array.isArray(list) ? [] : {}; | |
for (let i in list) if (list.hasOwnProperty(i)) out[i] = list[i](); | |
return out; | |
} | |
/** Provided by standard lib, replaces async.parallel() | |
* await parallel([ | |
* () => fetch('foo'), | |
* () => fetch('baz') | |
* ]) | |
*/ | |
export async function parallel(list) { | |
return await Promise.all(resolve(list)); | |
} | |
/** Replaces async.series() | |
* await series([ | |
* () => fetch('foo'), | |
* () => fetch('baz') | |
* ]) | |
*/ | |
export async function series(list) { | |
return await map(resolve(list), identity); | |
} |
@wizonesolutions - good catch, updated. Thanks!
you should publish this as a module, handy stuff
@duivvv I think I will! Will also likely transpile it via Kneden so it's nice and small.
Promise.all
doesn't invoke functions in the array. You could add map(fn => fn())
to get a list of promises/values to resolve with:
export async function parallel(list) {
return await Promise.all(list.map(fn => fn()));
}
That's all what you need. Just use functional approaches and principles. (I use Ramda, but all of these methods will be implemented pretty easy)
const a = [1,2,3,4];
Promise.of = x => Promise.resolve(x);
Promise.prototype.map = Promise.prototype.then;
Promise.prototype.ap = function(m) {
return this.then(f => m.then(v => f(v)));
};
// series
compose(sequence(Promise.of), map(Promise.of))(a).then(values => console.log(values)); // => [1,2,3,4]
// reduce
compose(map(reduce(add, 0)), sequence(Promise.of), map(Promise.of))(a).then(values => console.log(values)); // => 10
// map
compose(map(map(x => x * 10)), sequence(Promise.of), map(Promise.of))(a).then(values => console.log(values)); // => [10,20,30,40]
// filter
compose(map(filter(x => x % 2 === 0)), sequence(Promise.of), map(Promise.of))(a).then(values => console.log(values)); // => [2. 4]
The functions you're passing to reduce aren't returning anything
@jethrolarson - correct, reduce is being given a fourth argument here that ignores return values and instead uses a pass-by-reference accumulator only.
@dbrockman good catch! I've updated the gist to invoke those methods.
What do you think about changing the order of arguments, i.e. data comes last (like in Ramda)? :-)
@dpraimeyuu to simplify partial application?
@developit I think that, and make it works with pipes if we ever get them.
This is really cool and I've learned a lot already.
Thanks for putting this together and sharing it with the community! You rock!
@_@ man I have to read up on
await
andasync
because I cannot piece this together from my existing knowledge. btw, typo on line 49