timeable-promise
v1.7.4
Published
Various asynchronous operations with timeout support.
Maintainers
Readme
Timeable Promise
Collection of asynchronous utilities for managing concurrency, sequencing, and timing. Provides helpers for running tasks in parallel or sequential order, controlling execution with timeouts, and working with settled promise results.
Installation
yarn add timeable-promise || npm install --save timeable-promiseImporting
This package supports two styles of import:
- Named exports from the entry point:
import { chunk, ..., waitFor } from 'timeable-promise';- Direct path imports for individual utilities:
import chunk from 'timeable-promise/chunk';Use whichever style fits your project. Named exports are convenient when you need several utilities at once, while direct path imports can reduce bundle size if you only need one.
This package is written in TypeScript and provides type definitions out of the box. Your editor will offer autocomplete and type safety automatically.
For the full list of exports, refer to the API Call Graph.
API Call Graph
The diagram below shows how the exported utilities interact with each other:
graph LR
%% --- Subgraphs ---
subgraph Core
append["📎 append"]
outcome["🎯 outcome"]
toNumber["🔢 toNumber"]
end
subgraph Concurrency
concurrent["⚡ concurrent"]
concurrents["⚡⚡ concurrents"]
parallel["🔀 parallel"]
end
subgraph Sequencing
consecutive["➡️ consecutive"]
consecutives["➡️➡️ consecutives"]
sequential["⏩ sequential"]
end
poll["⏱️ poll"]
sleep["💤 sleep"]
waitFor["⏳ waitFor"]
untilSettledOrTimedOut["⏰ untilSettledOrTimedOut"]
%% --- Links ---
chunk["📦 chunk"] --> toNumber
concurrent --> chunk
concurrents --> concurrent
concurrents --> append
concurrents --> toNumber
concurrents --> outcome
consecutive --> outcome
consecutive --> toNumber
consecutives --> append
consecutives --> consecutive
consecutives --> toNumber
consecutives --> outcome
parallel --> chunk
parallel --> concurrent
parallel --> concurrents
parallel --> toNumber
parallel --> outcome
sequential --> chunk
sequential --> consecutive
sequential --> consecutives
sequential --> toNumber
sequential --> outcome
waitFor --> untilSettledOrTimedOut
%% --- Styling with original fills + black text ---
classDef core fill:#f9f,stroke:#333,stroke-width:2px,color:#000;
classDef concurrency fill:#bbf,stroke:#333,stroke-width:2px,color:#000;
classDef sequencing fill:#bfb,stroke:#333,stroke-width:2px,color:#000;
classDef utility fill:#ffd,stroke:#333,stroke-width:2px,color:#000;
class append,outcome,toNumber core;
class concurrent,concurrents,parallel concurrency;
class consecutive,consecutives,sequential sequencing;
class poll,sleep,waitFor,untilSettledOrTimedOut,chunk utility;Functions
append()
function append<T>(accumulator, array): T[];Defined in: append.ts:21
Appends items from one array onto the end of another.
Type Parameters
| Type Parameter | Description |
| ------ | ------ |
| T | The element type of the array. |
Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| accumulator | T[] | The accumulator array. |
| array | T[] | The array items that will be appended. |
Returns
T[]
The appended accumulator array.
Example
Basic append:
const appended = append<number>([1, 2], [3, 4]);
console.log(appended); // [1, 2, 3, 4]chunk()
function chunk<T, U>(array, size): U;Defined in: chunk.ts:26
Splits an array into chunks of a given size. The final chunk will contain the remaining elements.
Type Parameters
| Type Parameter | Default type | Description |
| ------ | ------ | ------ |
| T | - | The item type of the array. |
| U extends T[] | T[][] | T[] | The result type, which can be either: - T[] when no chunking is applied (size is 0 or omitted). - T[][] when chunking is applied (size > 0). |
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| array | T[] | undefined | The original array. |
| size | number | 0 | The chunk size (default = 0). |
Returns
U
A new array containing chunked subarrays, or the original array if size is 0.
Example
Chunk into pairs:
const chunked = chunk<number>([1, 2, 3, 4, 5], 2);
console.log(chunked); // [[1, 2], [3, 4], [5]]concurrent()
function concurrent<T, U>(
array,
executor,
concurrency): Promise<Settled<U>[]>;Defined in: concurrent.ts:52
Runs the executor concurrently across items in a single array. If a concurrency value is provided, items are grouped into chunks of that size and each chunk is processed in parallel. The output is always a settled results array, but the input shape differs: either individual items or grouped chunks.
Type Parameters
| Type Parameter | Default type | Description |
| ------ | ------ | ------ |
| T | - | The item type of the array. |
| U | T | The result type returned by the executor. |
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| array | T[] | undefined | The array items to be processed by executor. |
| executor | ItemExecutor<T, U> | undefined | Executor function applied to each chunk. |
| concurrency | number | 0 | The maximum concurrent execution size (default = 0). |
Returns
Promise<Settled<U>[]>
A promise resolving to an array of settled results.
Examples
With concurrency (groups of size 2):
const concurrentSettled1 = await concurrent<number>([1, 2, 3, 4, 5], async (chunk) => {
return chunk.map(x => x * 2);
}, 2);
console.log(concurrentSettled1);
// [
// { status: 'fulfilled', value: [2, 4] },
// { status: 'fulfilled', value: [6, 8] },
// { status: 'fulfilled', value: [10] }
// ]Without concurrency (each item processed individually):
const concurrentSettled2 = await concurrent<number>([1, 2, 3], async (value) => {
return value * 2;
});
console.log(concurrentSettled2);
// [
// { status: 'fulfilled', value: 2 },
// { status: 'fulfilled', value: 4 },
// { status: 'fulfilled', value: 6 }
// ]concurrents()
function concurrents<T, U>(
array,
executor,
concurrency): Promise<Settled<U>[]>;Defined in: concurrents.ts:55
Runs the executor concurrently across multiple groups of an array.
Internally calls concurrent for each group, then appends the results
together. While the output format looks similar to concurrent,
the orchestration differs: concurrents manages multiple concurrent runs,
whereas concurrent handles a single run.
Type Parameters
| Type Parameter | Default type | Description |
| ------ | ------ | ------ |
| T | - | The item type of the array. |
| U | T | The result type returned by the executor. |
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| array | T[] | undefined | The array groups to be processed by executor. |
| executor | ItemExecutor<T, U> | undefined | Executor function applied to each group. |
| concurrency | number | 0 | The maximum concurrent group size (default = 0). |
Returns
Promise<Settled<U>[]>
A promise resolving to an array of settled results.
Examples
With concurrency (groups of size 2):
const concurrentsSettled1 = await concurrents<number>([1, 2, 3, 4, 5], async (group) => {
return group.map(x => x * 2);
}, 2);
console.log(concurrentsSettled1);
// [
// { status: 'fulfilled', value: [2, 4] },
// { status: 'fulfilled', value: [6, 8] },
// { status: 'fulfilled', value: [10] }
// ]Without concurrency (each item treated as its own group):
const concurrentsSettled2 = await concurrents<number>([1, 2, 3], async (value) => {
return value * 2;
});
console.log(concurrentsSettled2);
// [
// { status: 'fulfilled', value: 2 },
// { status: 'fulfilled', value: 4 },
// { status: 'fulfilled', value: 6 }
// ]consecutive()
function consecutive<T, U>(
array,
executor,
concurrency): Promise<Settled<U>[]>;Defined in: consecutive.ts:52
Runs the executor sequentially across items in a single array. If a concurrency value is provided, items are grouped into chunks of that size and each group is processed one after another. While the output is always a settled results array, the input shape differs: either individual items or grouped chunks.
Type Parameters
| Type Parameter | Default type | Description |
| ------ | ------ | ------ |
| T | - | The item type of the array. |
| U | T | The result type returned by the executor. |
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| array | T[] | undefined | The array items to be processed by executor. |
| executor | ItemExecutor<T, U> | undefined | Executor function applied to each item or group. |
| concurrency | number | 0 | The maximum group size (default = 0). |
Returns
Promise<Settled<U>[]>
A promise resolving to an array of settled results.
Examples
With concurrency (groups of size 2):
const consecutiveSettled1 = await consecutive<number>([1, 2, 3, 4, 5], async (group) => {
return group.map(x => x * 2);
}, 2);
console.log(consecutiveSettled1);
// [
// { status: 'fulfilled', value: [2, 4] },
// { status: 'fulfilled', value: [6, 8] },
// { status: 'fulfilled', value: [10] }
// ]Without concurrency (each item processed one by one):
const consecutiveSettled2 = await consecutive<number>([1, 2, 3], async (value) => {
return value * 2;
});
console.log(consecutiveSettled2);
// [
// { status: 'fulfilled', value: 2 },
// { status: 'fulfilled', value: 4 },
// { status: 'fulfilled', value: 6 }
// ]consecutives()
function consecutives<T, U>(
array,
executor,
concurrency): Promise<Settled<U>[]>;Defined in: consecutives.ts:53
Runs the executor sequentially across multiple groups of an array.
Internally calls consecutive for each group, then appends the results together.
This means the output looks similar to consecutive, but the orchestration differs:
consecutives manages multiple consecutive runs, while consecutive handles a single run.
Type Parameters
| Type Parameter | Default type | Description |
| ------ | ------ | ------ |
| T | - | The item type of the array. |
| U | T | The result type returned by the executor. |
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| array | T[] | undefined | The array groups to be processed by executor. |
| executor | ItemExecutor<T, U> | undefined | Executor function applied to each group or item. |
| concurrency | number | 0 | The maximum group size (default = 0). |
Returns
Promise<Settled<U>[]>
A promise resolving to an array of settled results.
Examples
With concurrency (groups of size 2):
const consecutivesSettled1 = await consecutives<number>([1, 2, 3, 4, 5], async (group) => {
return group.map(x => x * 2);
}, 2);
console.log(consecutivesSettled1);
// [
// { status: 'fulfilled', value: [2, 4] },
// { status: 'fulfilled', value: [6, 8] },
// { status: 'fulfilled', value: [10] }
// ]Without concurrency (each item treated as its own group):
const consecutivesSettled2 = await consecutives<number>([1, 2, 3], async (value) => {
return value * 2;
});
console.log(consecutivesSettled2);
// [
// { status: 'fulfilled', value: 2 },
// { status: 'fulfilled', value: 4 },
// { status: 'fulfilled', value: 6 }
// ]outcome()
function outcome<T, U>(executor, ...args): Promise<Settled<U>>;Defined in: outcome.ts:42
Executes an executor and returns a PromiseSettledResult-like outcome.
Type Parameters
| Type Parameter | Default type | Description |
| ------ | ------ | ------ |
| T | - | The item type of the array. |
| U | T | The result type returned by the executor. |
Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| executor | ItemExecutor<T, U> | Function to execute. |
| ...args | [T[], number, T[][], PromiseSettledResult<U>[]] | Arguments passed to the executor. |
Returns
Promise<Settled<U>>
A settled outcome object.
Examples
Fulfilled outcome:
const ok = await outcome<number>(async (x: number) => x * 2, 5);
console.log(ok); // { status: 'fulfilled', value: 10 }Rejected outcome:
const err = await outcome(() => { throw new Error('fail'); });
console.log(err); // { reason: Error('fail'), status: 'rejected' }parallel()
function parallel<T, U>(
array,
executor,
concurrency): Promise<Settled<U>[]>;Defined in: parallel.ts:54
Provides parallel execution of an executor across array items.
If a concurrency value is provided, items are grouped into chunks of that size
and processed concurrently via concurrents. Otherwise, the entire array is
processed concurrently via concurrent.
Type Parameters
| Type Parameter | Default type | Description |
| ------ | ------ | ------ |
| T | - | The item type of the array. |
| U | T | The result type returned by the executor. |
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| array | T[] | undefined | The array that is being processed in parallel. |
| executor | ItemExecutor<T, U> | undefined | Executor function applied to each item or group. |
| concurrency | number | 0 | The maximum group size (default = 0). |
Returns
Promise<Settled<U>[]>
A promise resolving to an array of settled results.
Examples
With concurrency (groups of size 2):
const parallelSettled1 = await parallel<number>([1, 2, 3, 4, 5], async (group) => {
return group.map(x => x * 2);
}, 2);
console.log(parallelSettled1);
// [
// { status: 'fulfilled', value: [2, 4] },
// { status: 'fulfilled', value: [6, 8] },
// { status: 'fulfilled', value: [10] }
// ]Without concurrency (all items processed concurrently):
const parallelSettled2 = await parallel<number>([1, 2, 3], async (value) => {
return value * 2;
});
console.log(parallelSettled2);
// [
// { status: 'fulfilled', value: 2 },
// { status: 'fulfilled', value: 4 },
// { status: 'fulfilled', value: 6 }
// ]poll()
function poll(
executor,
interval,
immediately): PollHandle;Defined in: poll.ts:41
Provides polling support without congestion when the executor takes longer
than the interval. The executor receives a stopped function to check
if polling has been stopped.
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| executor | PollExecutor | undefined | Function invoked on each poll. Receives a stopped function. |
| interval | number | 1000 | Delay interval in milliseconds (default = 1000). |
| immediately | boolean | false | Whether to run executor immediately at the beginning (default = false). |
Returns
An object with a stop function to end polling.
Example
Basic polling with stop control:
const timer = poll((stopped) => {
// Do something promising here...
if (!stopped()) {
// Do something when polling is not stopped...
}
}, 100);
setTimeout(() => {
// Simulate the end of polling.
timer.stop();
}, 1000);sequential()
function sequential<T, U>(
array,
executor,
concurrency): Promise<Settled<U>[]>;Defined in: sequential.ts:54
Provides sequential execution of an executor across array items.
If a concurrency value is provided, items are grouped into chunks of that size
and processed sequentially via consecutives. Otherwise, the entire array is
processed sequentially via consecutive.
Type Parameters
| Type Parameter | Default type | Description |
| ------ | ------ | ------ |
| T | - | The item type of the array. |
| U | T | The result type returned by the executor. |
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| array | T[] | undefined | The array that is being processed sequentially. |
| executor | ItemExecutor<T, U> | undefined | Executor function applied to each item or group. |
| concurrency | number | 0 | The maximum group size (default = 0). |
Returns
Promise<Settled<U>[]>
A promise resolving to an array of settled results.
Examples
With concurrency (groups of size 2):
const sequentialSettled1 = await sequential<number>([1, 2, 3, 4, 5], async (group) => {
return group.map(x => x * 2);
}, 2);
console.log(sequentialSettled1);
// [
// { status: 'fulfilled', value: [2, 4] },
// { status: 'fulfilled', value: [6, 8] },
// { status: 'fulfilled', value: [10] }
// ]Without concurrency (all items processed one by one):
const sequentialSettled2 = await sequential<number>([1, 2, 3], async (value) => {
return value * 2;
});
console.log(sequentialSettled2);
// [
// { status: 'fulfilled', value: 2 },
// { status: 'fulfilled', value: 4 },
// { status: 'fulfilled', value: 6 }
// ]sleep()
function sleep(timeout): Promise<void>;Defined in: sleep.ts:20
Suspends execution for the given timeout duration.
Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| timeout | number | Timeout in milliseconds. |
Returns
Promise<void>
A promise that resolves after the given timeout.
Example
Sleep for 1 second:
console.time('sleep');
await sleep(1000);
console.timeEnd('sleep');toNumber()
function toNumber(value, defaultValue): number;Defined in: toNumber.ts:30
Converts a value to a number. If conversion fails, returns the default value.
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| value | unknown | undefined | The value to convert. |
| defaultValue | number | 0 | The fallback if conversion is invalid (default = 0). |
Returns
number
A numeric value.
Examples
Convert string to number:
console.log(toNumber('42')); // 42Fallback value when conversion fails:
console.log(toNumber('abc', 10)); // 10Null input defaults to 0:
console.log(toNumber(null)); // 0untilSettledOrTimedOut()
function untilSettledOrTimedOut<T>(
promiseExecutor,
timeoutExecutor,
timeout): Promise<T>;Defined in: untilSettledOrTimedOut.ts:67
Provides timeout support for a Promise. The executor runs until either it settles or the timeout expires, in which case the timeoutExecutor is invoked.
Type Parameters
| Type Parameter | Description |
| ------ | ------ |
| T | The type of the resolved return value. |
Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| promiseExecutor | PromiseExecutor<T> | Executor function, receives resolve, reject, and a pending function. |
| timeoutExecutor | TimeoutExecutor<T> | Function invoked if timeout occurs, receives resolve and reject. |
| timeout | number | Timeout in milliseconds. |
Returns
Promise<T>
A promise resolving or rejecting with the executor or timeoutExecutor result.
Example
Executor with timeout fallback:
const executor = (resolve, reject, pending) => {
// Do something promising here...
if (pending()) {
try {
// Do something more promising here...
resolve(true);
} catch (ex) {
reject(false);
}
}
};
const timeoutExecutor = (resolve, reject) => {
try {
resolve(true);
} catch (ex) {
reject(false);
}
};
const timeout = 5000;
const response = await untilSettledOrTimedOut<boolean>(executor, timeoutExecutor, timeout)
.catch(ex => console.log('nay :(', ex));
console.log(`resolved with ${response}, yay!`);waitFor()
function waitFor(
predicate,
timeout,
interval): Promise<void>;Defined in: waitFor.ts:34
Wait until a predicate returns true or timeout occurs.
Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| predicate | () => boolean | undefined | Function returning a boolean, checked repeatedly. |
| timeout | number | undefined | Max time to wait in ms. |
| interval | number | 1000 | Polling interval in ms (default = 1000). |
Returns
Promise<void>
A promise that resolves when predicate is true or timeout expires.
Example
Wait for predicate to become true:
let inflight = true;
const predicate = () => !inflight;
const timeout = 5000;
setTimeout(() => {
inflight = false; // long process done
}, 1000);
console.time('waitFor');
await waitFor(predicate, timeout, 200);
console.timeEnd('waitFor');Type Aliases
ItemExecutor()
type ItemExecutor<T, U> = (value, index, array, accumulator?) => Promise<U> | U;Defined in: outcome.ts:8
Type Parameters
| Type Parameter | Default type |
| ------ | ------ |
| T | - |
| U | T |
Parameters
| Parameter | Type |
| ------ | ------ |
| value | T[] |
| index | number |
| array | T[][] |
| accumulator? | PromiseSettledResult<U>[] |
Returns
Promise<U> | U
PollExecutor()
type PollExecutor = (stopped) => Promise<void> | void;Defined in: poll.ts:9
Parameters
| Parameter | Type |
| ------ | ------ |
| stopped | () => boolean |
Returns
Promise<void> | void
PollHandle
type PollHandle = {
stop: () => void;
};Defined in: poll.ts:11
Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| stop | () => void | poll.ts:12 |
PromiseConstructor
type PromiseConstructor<T> = ConstructorParameters<typeof Promise>[0];Defined in: untilSettledOrTimedOut.ts:8
Type Parameters
| Type Parameter |
| ------ |
| T |
PromiseExecutor()
type PromiseExecutor<T> = (resolve, reject, pending) => void;Defined in: untilSettledOrTimedOut.ts:10
Type Parameters
| Type Parameter |
| ------ |
| T |
Parameters
| Parameter | Type |
| ------ | ------ |
| resolve | Parameters<PromiseConstructor<T>>[0] |
| reject | Parameters<PromiseConstructor<T>>[1] |
| pending | () => boolean |
Returns
void
Settled
type Settled<T> = PromiseSettledResult<T>;Defined in: outcome.ts:19
Type Parameters
| Type Parameter |
| ------ |
| T |
TimeoutExecutor()
type TimeoutExecutor<T> = (resolve, reject) => void;Defined in: untilSettledOrTimedOut.ts:19
Type Parameters
| Type Parameter |
| ------ |
| T |
Parameters
| Parameter | Type |
| ------ | ------ |
| resolve | Parameters<PromiseConstructor<T>>[0] |
| reject | Parameters<PromiseConstructor<T>>[1] |
Returns
void
Development Dependencies
You will need to install Node.js as a local
development dependency. The npm package manager comes bundled with all
recent releases of Node.js. You can also use yarn
as a package manager.
yarn or npm install will attempt to resolve any npm module dependencies
that have been declared in the project's package.json file, installing them
into the node_modules folder.
yarn || npm installRun Leak, Lint, Performance, Type and Unit Tests
To make sure we did not break anything, let's run all the tests:
yarn test || npm run testRun leak tests only:
yarn test:leak || npm run test:leakRun linter only:
yarn test:lint || npm run test:lintRun performance tests only:
yarn test:perf || npm run test:perfRun type check only:
yarn test:type || npm run test:typeRun unit tests only:
yarn test:unit || npm run test:unitContributing
If you would like to contribute code to Timeable Promise repository you can do so through GitHub by forking the repository and sending a pull request.
If you do not agree to Contribution Agreement, do not contribute any code to Timeable Promise repository.
When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. Please also include appropriate test cases.
That's it! Thank you for your contribution!
License
Copyright (c) 2018-2025 Richard Huang.
This module is free software, licensed under: GNU Affero General Public License (AGPL-3.0).
Documentation and other similar content are provided under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
