Skip to content

Instantly share code, notes, and snippets.

@developit
Last active February 19, 2020 00:43
Show Gist options
  • Star 46 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save developit/7a6e48654b88002a835f8f6bc4535a6d to your computer and use it in GitHub Desktop.
Save developit/7a6e48654b88002a835f8f6bc4535a6d to your computer and use it in GitHub Desktop.
Async Array utilities in async/await. Now available as an npm package: https://github.com/developit/asyncro
/** 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
Copy link

@_@ man I have to read up on await and async because I cannot piece this together from my existing knowledge. btw, typo on line 49

@developit
Copy link
Author

@wizonesolutions - good catch, updated. Thanks!

@geoffreydhuyvetters
Copy link

you should publish this as a module, handy stuff

@developit
Copy link
Author

@duivvv I think I will! Will also likely transpile it via Kneden so it's nice and small.

@dbrockman
Copy link

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()));
}

@xgrommx
Copy link

xgrommx commented Oct 21, 2016

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]

@jethrolarson
Copy link

The functions you're passing to reduce aren't returning anything

@developit
Copy link
Author

@jethrolarson - correct, reduce is being given a fourth argument here that ignores return values and instead uses a pass-by-reference accumulator only.

@developit
Copy link
Author

@dbrockman good catch! I've updated the gist to invoke those methods.

@dpraimeyuu
Copy link

What do you think about changing the order of arguments, i.e. data comes last (like in Ramda)? :-)

@developit
Copy link
Author

@dpraimeyuu to simplify partial application?

@viktor-evdokimov
Copy link

@developit I think that, and make it works with pipes if we ever get them.

@peterpme
Copy link

This is really cool and I've learned a lot already.

Thanks for putting this together and sharing it with the community! You rock!

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