Skip to content

Instantly share code, notes, and snippets.

@jhurliman
Created January 25, 2016 05:06
Show Gist options
  • Save jhurliman/82540feafc39ef03634c to your computer and use it in GitHub Desktop.
Save jhurliman/82540feafc39ef03634c to your computer and use it in GitHub Desktop.
ES7 implementation of Array.map() and the equivalent for objects
import PromisePool from 'es6-promise-pool'
/**
* Like Array.map() but supports promises and concurrency limiting.
* @param {array} array - Input array to map.
* @param {function} asyncFn(currentValue, index, array) - Called once for each
* value in the array.
* @param {number} [concurrencyLimit] - Optional cap on the number of
* asynchronous methods to execute at once.
* @returns {array} An array containing the mapped output values.
*/
export async function mapAsync (array, asyncFn, concurrencyLimit) {
concurrencyLimit = concurrencyLimit || Number.MAX_SAFE_INTEGER
let outputError
const output = new Array(array.length)
function createAssigner (i) { return function (value) { output[i] = value } }
function setError (err) { outputError = (err instanceof Error) ? err : new Error(err) }
const generator = function *() {
for (let i = 0; i < array.length; i++) {
const promiseOrValue = asyncFn(array[i], i, array)
yield Promise.resolve(promiseOrValue).then(createAssigner(i), setError)
if (outputError) { return }
}
}
const pool = new PromisePool(generator(), concurrencyLimit)
await new Promise(resolve => pool.start().then(_ => resolve()))
if (outputError) throw outputError
return output
}
/**
* Like Array.map() but for objects and supporting promises and concurrency
* limiting.
* @param {object} obj - Input object to map.
* @param {function} asyncFn(currentValue, key, obj) - Called once for each
* property in the object.
* @param {number} [concurrencyLimit] - Optional cap on the number of
* asynchronous methods to execute at once.
* @returns {object} An object containing the mapped output properties.
*/
export async function mapPropsAsync (obj, asyncFn, concurrencyLimit) {
concurrencyLimit = concurrencyLimit || Number.MAX_SAFE_INTEGER
const keys = Object.keys(obj)
const values = keys.map(key => obj[key])
let outputError
const outValues = new Array(values.length)
function createAssigner (i) { return function (value) { outValues[i] = value } }
function setError (err) { outputError = (err instanceof Error) ? err : new Error(err) }
const generator = function *() {
for (let i = 0; i < values.length; i++) {
const promiseOrValue = asyncFn(values[i], keys[i], obj)
yield Promise.resolve(promiseOrValue).then(createAssigner(i), setError)
if (outputError) { return }
}
}
const pool = new PromisePool(generator(), concurrencyLimit)
await new Promise(resolve => pool.start().then(_ => resolve()))
if (outputError) throw outputError
const output = {}
keys.forEach((key, i) => output[key] = outValues[i])
return output
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment