awaitless v1.6.1
Awaitless
Awaitless is a lightweight, zero-dependency Promises utility that provides a set of useful operations on Promises, geared towards projects that do not have access to async-await.
This is particularly useful for projects that transpile from a pre-ES6 versioned language, but target newer browsers or run on a more up-to-date version of Node that still supports Promises.
Table of Contents
Notes
This module does not supply a promises implementation, but only provides a set of useful operations for promises. It is recommended to take any of the many promises implementations before using this module, if your project does not have promises already.
This project uses Promise
directly, so if you are using a promises implementation, make sure to overwrite Promise
to the implementation you've chosen.
This project implements none of the provided functions using async/await.
Documentation
default
- method:
default(promiseFuncs)
- description: This is the same as
chain
, but can also be used to access any of the methods below: - params: (see
chain
) example:
import awaitless from "awaitless"; /** * These exist: * - awaitless.chain * - awaitless.doWhilst * - awaitless.forEach * - awaitless.map * - awaitless.toPromise * - awaitless.whilst */ awaitless([ { thing0: () => "Cat", thing1: () => new Promise((resolve) => setTimeout(() => resolve("Dog"), 1000)), thing2: () => new Promise((resolve) => setTimeout(() => resolve("Giraffe"), 2000)) }, ({ thing0, thing2 }) => expect(`${thing0}${thing2}`).toBe("CatGiraffe"), { thing3: () => "Camel", thing4: () => new Promise((resolve) => setTimeout(() => resolve("Turtle"), 1000)) }, ({ thing0, thing1, thing2, thing3, thing4 }) => `${thing0}${thing1}${thing2}${thing3}${thing4}` ]).then((result) => result === "CatDogGiraffeCamelTurtle");
chain
- method:
chain(promiseFuncs)
- description: This is functionally the same as promise chaining, but supports a clean signature for parallelly ran promises, variable assignment, and breaking and returning early out of the promise chain.
- params:
promiseFuncs
: An array of either objects mapped to functions, or functions.
- returns:
Promise<any>
example:
Standard use:
import { chain } from "awaitless"; chain([ // These execute in parallel { thing0: () => "Cat", thing1: () => new Promise((resolve) => setTimeout(() => resolve("Dog"), 1000)), thing2: () => new Promise((resolve) => setTimeout(() => resolve("Giraffe"), 2000)) }, // Assignments will be available in all subsequent promiseFuncs functions. ({ thing0, thing2 }) => expect(`${thing0}${thing2}`).toBe("CatGiraffe"), { thing3: ({ thing0 }) => `${thing0}fish`, thing4: () => new Promise((resolve) => setTimeout(() => resolve("Turtle"), 1000)) }, // Results from assignment objects are available in all subsequent functions ({ thing0, thing1, thing2, thing3, thing4 }) => `${thing0}${thing1}${thing2}${thing3}${thing4}` ]).then((result) => result === "CatDogGiraffeCatfishTurtle");
Breaking the promise chain:
import { chain } from "awaitless"; chain([ { thing0: () => new Promise((resolve) => setTimeout(() => resolve("Dog"), 1000)) }, // This will terminate the promise chain and resolve with the value of thing0 ("Dog") ({ thing0 }, { $break }) => $break(thing0), // This will not execute () => console.log("Hello!"), // Cannot break in an assignment object, must break in a function { thing1: (__, { $break }) => $break("This will throw an error!") } ]).then((result) => result === "Dog");
Assigning manually (not recommended):
import { chain } from "awaitless"; chain([ { thing0: (__, { $assign }) => { return new Promise((resolve) => { try { resolve(promiseFnThatMightError("Dog")); } catch (err) { $assign("didError", true); } }) } }, // Unlike $break, $assign is available in non-assignment objects as well ({ thing0, didError = false }, { $assign }) => { if (didError) { // Do something } else { return thing0; } } ]).then((result) => // result is the value of thing0 );
doWhilst
- method:
doWhilst(promiseFn, condFn, options)
- description: The post-check version of whilst.
- params:
promiseFn
: A function (typed(currentValue: any) => Promise<any>
) which is called each timecondFn
passes. Passes the previous return value ofpromiseFn
.condFn
: A function which returnsPromise<boolean> | boolean
that takes the last return value ofpromiseFn
that is run after each execution ofpromiseFn
.options
: An optional options objectinitialValue
(any
, default:null
): The initial value to invokepromiseFn
with.maxRetry
(number
, default:Infinity
): The number of times to retry, until an error is thrown.
- returns:
Promise<any>
example:
import { doWhilst } from "awaitless"; doWhilst( (current) => new Promise((resolve) => setTimeout(() => resolve(++current), 1000)), (current) => current < 5, { initialValue: 0 } ).then((result) => result === 5);
filter
- method:
filter(items, filterFn, options)
- description: Iterates over an array of items, and invokes a filter function that returns a boolean promise to determine whether to filter each time. Filtered items maintain their original order (this is not the same as index, because the result array will be of equal or smaller length).
- params:
items
: An array of anythingfilterFn
: A function (typed(item: any, index: number) => Promise<boolean>
) that gets invoked with each item.options
: An optional options objectconcurrency
(number
, default:1
): Runs thefilterFn
with the specified concurrency limit. If everything should be parallel, set this toInfinity
.filter
will still respect the original order of items, regardless of when order each item is completed.
- returns:
Promise<any[]>
forEach
- method:
forEach(items, promiseFn, options)
- description: Iterates over an array of items, and invokes a function that returns a promise for each item.
- params:
items
: An array of anythingpromiseFn
: A function (typed(item: any, index: number) => Promise<void>
), that gets invoked with each itemoptions
: An optional options objectconcurrency
(number
, default:1
): Runs thepromiseFn
with the specified concurrency limit. If everything should be parallel, set this toInfinity
.
- returns:
Promise<void>
example
import { forEach } from "awaitless"; const result = []; forEach( [300, 200, 100], (value) => new Promise((resolve) => setTimeout(() => { result.push(value); resolve(); }, value)), { concurrency: 2 } ).then(() => // result is [200, 300, 100]);
map
- method:
map(items, promiseFn, options)
- description: Iterates over an array of items, and invokes a function that returns a promise to map each item. This will return items in the same order, regardless of what order the items complete.
- params:
items
: An array of anythingpromiseFn
: A function (typed(item: any, index: number) => Promise<any>
), that gets invoked with each itemoptions
: An optional options objectconcurrency
(number
, default:1
): Runs thepromiseFn
with the specified concurrency limit. If everything should be parallel, set this toInfinity
.
- returns:
Promise<any[]>
example
import { map } from "awaitless"; map( [300, 200, 100], (value) => new Promise((resolve) => setTimeout(() => resolve(value), value)), { concurrency: 2 } ).then((result) => // result is [300, 200, 100]);
reduce
- method:
reduce(items, reduceFn, initialValue)
- description: Iterates over an array of items, and invokes a reducer function that returns a promise to reduce the items. This is nearly identical to
Array.reduce
, except is designed to work with a promise function. - params:
items
: An array of anythingreduceFn
: A function (typed(accumulator: any, item: any, index: number) => Promise<any>
), that gets invoked with the current accumulated value and each item.initialValue
: An optional initial value to use as the first argument to thereduceFn
. If undefined, the first element will be used as theinitialValue
and skipped in the first call of thereduceFn
.
- returns:
Promise<any>
example:
import { reduce } from "awaitless"; reduce( [1, 2, 3], (acc, item) => new Promise((resolve) => setTimeout(() => resolve(`${acc}${item}`), 1000)), "" ).then((result) => result === "123");
toPromise
- method:
toPromise(fn, thisArg)
- description: Converts a callback function to a promise function.
- params:
fn
: A function with a callback (typed as(err: Error | string | null, result: any) => void
) as a last parameter.thisArg?
: An object to bindthis
to, if needed
- returns:
(...args: any[]) => Promise<any>
example:
import { toPromise } from "awaitless"; const fnWithCallback = (firstName, lastName, callback) => { setTimeout(() => { const isBadName = firstName === "badName"; if (isBadName) { callback("Error: Name is bad name"); } callback(null, `${firstName}_${lastName}`); }, 1000); }; const promisifiedFn = toPromise(fnWithCallback); promisifiedFn("Bobbathan", "Dole") .then((result) => result === "Bobbathan_Dole") .catch((err) => console.log(err));
whilst
- method:
whilst(condFn, promiseFn, options)
- description: Repeatedly calls
promiseFn
whilecondFn
returnstrue
. This returns that last return value ofpromiseFn
- params:
condFn
: A function which returnsPromise<boolean> | boolean
that takes the last return value ofpromiseFn
that is run after each execution ofpromiseFn
.promiseFn
: A function (typed(currentValue: any) => Promise<any>
) which is called each timecondFn
passes. Passes the previous return value ofpromiseFn
.options
: An optional options objectinitialValue
(any
, default:null
): The initial value to invokepromiseFn
with.maxRetry
(number
, default:Infinity
): The number of times to retry, until an error is thrown.
- returns:
Promise<any>
example:
import { whilst } from "awaitless"; whilst( (current) => current < 5, (current) => new Promise((resolve) => setTimeout(() => resolve(++current), 1000)), { initialValue: 0 } ).then((result) => result === 5);