Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

Copy link

commented Oct 20, 2016

@_@ 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

This comment has been minimized.

Copy link
Owner Author

commented Oct 20, 2016

@wizonesolutions - good catch, updated. Thanks!

@duivvv

This comment has been minimized.

Copy link

commented Oct 20, 2016

you should publish this as a module, handy stuff

@developit

This comment has been minimized.

Copy link
Owner Author

commented Oct 20, 2016

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

@dbrockman

This comment has been minimized.

Copy link

commented Oct 21, 2016

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

commented Oct 21, 2016

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

@developit

This comment has been minimized.

Copy link
Owner Author

commented Oct 21, 2016

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

@developit

This comment has been minimized.

Copy link
Owner Author

commented Oct 21, 2016

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

@dpraimeyuu

This comment has been minimized.

Copy link

commented Oct 21, 2016

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

@developit

This comment has been minimized.

Copy link
Owner Author

commented Oct 21, 2016

@dpraimeyuu to simplify partial application?

@viktor-evdokimov

This comment has been minimized.

Copy link

commented Oct 21, 2016

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

@peterpme

This comment has been minimized.

Copy link

commented Oct 21, 2016

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
You can’t perform that action at this time.