Skip to content

rickypc/timeable-promise

Repository files navigation

Timeable Promise

Version Downloads Dependencies Style TypeScript Checks Coverage Vulnerabilities License

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-promise

Importing

This package supports two styles of import:

  1. Named exports from the entry point:
import { chunk, ..., waitFor } from 'timeable-promise';
  1. 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;
Loading

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

PollHandle

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'));        // 42

Fallback value when conversion fails:

console.log(toNumber('abc', 10));   // 10

Null input defaults to 0:

console.log(toNumber(null));        // 0

untilSettledOrTimedOut()

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 install

Run 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 test

Run leak tests only:

yarn test:leak || npm run test:leak

Run linter only:

yarn test:lint || npm run test:lint

Run performance tests only:

yarn test:perf || npm run test:perf

Run type check only:

yarn test:type || npm run test:type

Run unit tests only:

yarn test:unit || npm run test:unit

Contributing

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 © 2018 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.