or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-when

A lightweight Promises/A+ and when() implementation, plus other async goodies.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/when@3.7.x

To install, run

npx @tessl/cli install tessl/npm-when@3.7.0

index.mddocs/

When.js

Overview

When.js is a battle-tested Promises/A+ and when() implementation that provides a comprehensive suite of asynchronous utilities for JavaScript. It offers a powerful combination of small size, high performance, and rich features for managing complex asynchronous flows through promise chaining, error handling, and control flow utilities.

Package Information

  • Name: when
  • Type: Promise library
  • Language: JavaScript
  • Installation: npm install when

Core Imports

// ESM
import when from "when";
import { resolve, reject, all, map } from "when";

// CommonJS
const when = require("when");
const { resolve, reject, all, map } = when;

// AMD
define(['when'], function(when) {
  // use when
});

Basic Usage

// Create and transform promises
when(someValue)
  .then(result => result * 2)
  .catch(error => console.error('Error:', error));

// Promise creation
const promise = when.resolve("hello world");
const rejected = when.reject(new Error("failed"));

// Array processing
when.all([promise1, promise2, promise3])
  .then(results => console.log('All resolved:', results));

Core Promise API

Main when() Function

/**
 * Get a trusted promise for value x, or transform x with callbacks
 * @param x - Value or promise to resolve
 * @param onFulfilled - Success callback  
 * @param onRejected - Error callback
 * @param onProgress - Progress callback (deprecated)
 * @returns Promise for the result
 */
function when<T, U>(
  x: T | Promise<T>, 
  onFulfilled?: (value: T) => U | Promise<U>,
  onRejected?: (reason: any) => U | Promise<U>,
  onProgress?: (update: any) => void
): Promise<U>;

Promise Creation

/**
 * Create a new promise with a resolver function
 * @param resolver - Function that receives resolve, reject, notify callbacks
 * @returns New promise
 */
function promise<T>(
  resolver: (
    resolve: (value: T) => void,
    reject: (reason: any) => void,
    notify: (progress: any) => void
  ) => void
): Promise<T>;

/**
 * Create a resolved promise
 * @param value - Value to resolve with
 * @returns Promise resolved with value
 */
function resolve<T>(value: T | Promise<T>): Promise<T>;

/**
 * Create a rejected promise  
 * @param reason - Rejection reason
 * @returns Promise rejected with reason
 */
function reject<T = never>(reason: any): Promise<T>;

Deferred Objects

interface Deferred<T> {
  /** The underlying promise */
  promise: Promise<T>;
  /** Resolve the promise */
  resolve: (value: T) => void;
  /** Reject the promise */
  reject: (reason: any) => void;
  /** Notify progress (deprecated) */
  notify: (progress: any) => void;
  /** Resolver object with resolve/reject/notify methods */
  resolver: {
    resolve: (value: T) => void;
    reject: (reason: any) => void; 
    notify: (progress: any) => void;
  };
}

/**
 * Create a deferred promise/resolver pair
 * @returns Deferred object with promise and resolver methods
 */
function defer<T>(): Deferred<T>;

Function Lifting and Execution

Function Lifting

// Import from when/function module  
import { lift, apply, call, compose } from "when/function";

/**
 * Lift a function to work with promises as arguments and return promises
 * @param f - Function to lift
 * @returns Promise-aware version of the function
 */
function lift<TArgs extends any[], TResult>(
  f: (...args: TArgs) => TResult
): (...args: { [K in keyof TArgs]: TArgs[K] | Promise<TArgs[K]> }) => Promise<TResult>;

/**
 * Apply a function with args array and return a promise for its result  
 * @param f - Function to apply
 * @param args - Arguments array to pass to function
 * @returns Promise for function result
 */
function apply<TArgs extends any[], TResult>(
  f: (...args: TArgs) => TResult,
  args: TArgs
): Promise<TResult>;

/**
 * Call a function and return a promise for its result (alias for when.try)
 * @param f - Function to call
 * @param args - Arguments to pass to function
 * @returns Promise for function result
 */
function call<TResult>(f: () => TResult): Promise<TResult>;
function call<T1, TResult>(f: (arg1: T1) => TResult, arg1: T1): Promise<TResult>;

/**
 * Compose functions into a promise-aware pipeline
 * @param f - First function to receive arguments
 * @param funcs - Additional functions to compose in sequence
 * @returns Composed function that returns a promise
 */
function compose<TArgs extends any[], TResult>(
  f: (...args: TArgs) => any,
  ...funcs: ((arg: any) => any)[]
): (...args: TArgs) => Promise<TResult>;

Array and Collection Operations

Promise Arrays

/**
 * Resolve all promises in an array
 * @param promises - Array of promises or values
 * @returns Promise for array of resolved values
 */
function all<T>(promises: (T | Promise<T>)[]): Promise<T[]>;

/**
 * Settle all promises (resolve or reject) and return outcome descriptors
 * @param promises - Array of promises or values  
 * @returns Promise for array of settlement descriptors
 */
function settle<T>(promises: (T | Promise<T>)[]): Promise<SettleDescriptor<T>[]>;

interface SettleDescriptor<T> {
  state: "fulfilled" | "rejected";
  value?: T;
  reason?: any;
}

/**
 * Join multiple promises (variadic version of all)
 * @param promises - Promise arguments to join
 * @returns Promise for array of resolved values
 */
function join<T extends any[]>(...promises: { [K in keyof T]: T[K] | Promise<T[K]> }): Promise<T>;

Promise Racing

/**
 * Race promises, resolving with first to settle  
 * @param promises - Array of promises to race
 * @returns Promise that resolves/rejects with first settlement
 */
function race<T>(promises: (T | Promise<T>)[]): Promise<T>;

/**
 * Resolve with first promise to fulfill (ignores rejections until all reject)
 * @param promises - Array of promises
 * @returns Promise for first fulfilled value
 */
function any<T>(promises: (T | Promise<T>)[]): Promise<T>;

/**
 * Resolve with first N promises to fulfill
 * @param promises - Array of promises
 * @param count - Number of fulfillments needed
 * @returns Promise for array of first N fulfilled values
 */  
function some<T>(promises: (T | Promise<T>)[], count: number): Promise<T[]>;

Array Processing

/**
 * Promise-aware array map function
 * @param promises - Array of promises or values
 * @param mapFunc - Mapping function (may return promise)
 * @returns Promise for array of mapped values
 */
function map<T, U>(
  promises: (T | Promise<T>)[], 
  mapFunc: (value: T, index: number) => U | Promise<U>
): Promise<U[]>;

/**
 * Promise-aware array filter function
 * @param promises - Array of promises or values  
 * @param predicate - Filter predicate (may return promise)
 * @returns Promise for array of filtered values
 */
function filter<T>(
  promises: (T | Promise<T>)[],
  predicate: (value: T, index: number) => boolean | Promise<boolean>
): Promise<T[]>;

/**
 * Promise-aware array reduce function
 * @param promises - Array of promises or values
 * @param reducer - Reducer function (may return promise)
 * @param initialValue - Initial accumulator value
 * @returns Promise for final reduced value
 */
function reduce<T, U>(
  promises: (T | Promise<T>)[],
  reducer: (accumulator: U, value: T, index: number) => U | Promise<U>,
  initialValue: U
): Promise<U>;

/**
 * Promise-aware array reduceRight function  
 * @param promises - Array of promises or values
 * @param reducer - Reducer function (may return promise)
 * @param initialValue - Initial accumulator value
 * @returns Promise for final reduced value
 */
function reduceRight<T, U>(
  promises: (T | Promise<T>)[],
  reducer: (accumulator: U, value: T, index: number) => U | Promise<U>, 
  initialValue: U
): Promise<U>;

Promise Instance Methods

Core Methods

interface Promise<T> {
  /**
   * Standard Promises/A+ then method
   * @param onFulfilled - Success callback
   * @param onRejected - Error callback  
   * @param onProgress - Progress callback (deprecated)
   * @returns New promise for callback result
   */
  then<U>(
    onFulfilled?: (value: T) => U | Promise<U>,
    onRejected?: (reason: any) => U | Promise<U>,
    onProgress?: (progress: any) => void
  ): Promise<U>;

  /**
   * Catch promise rejections
   * @param onRejected - Error callback
   * @returns New promise  
   */
  catch<U>(onRejected: (reason: any) => U | Promise<U>): Promise<T | U>;

  /**
   * Execute callback regardless of outcome
   * @param onFinally - Cleanup callback
   * @returns Promise with original value/reason
   */
  finally(onFinally: () => void | Promise<void>): Promise<T>;
}

Timing Methods

interface Promise<T> {
  /**
   * Delay promise resolution
   * @param ms - Delay in milliseconds
   * @returns Promise that resolves after delay with same value
   */
  delay(ms: number): Promise<T>;

  /**
   * Add timeout to promise
   * @param ms - Timeout in milliseconds
   * @param reason - Custom timeout reason
   * @returns Promise that rejects if timeout exceeded
   */
  timeout(ms: number, reason?: any): Promise<T>;
}

Inspection and Utilities

interface PromiseInspection<T> {
  /** Current state of the promise */
  state: "pending" | "fulfilled" | "rejected";
  /** Resolved value (only if fulfilled) */
  value?: T;
  /** Rejection reason (only if rejected) */  
  reason?: any;
}

interface Promise<T> {
  /**
   * Synchronously inspect promise state
   * @returns Inspection object with state and value/reason
   */
  inspect(): PromiseInspection<T>;

  /**
   * Execute side effect without changing promise value
   * @param onFulfilled - Side effect callback
   * @returns Promise with original value
   */
  tap(onFulfilled: (value: T) => void | Promise<void>): Promise<T>;

  /**
   * Spread array result as function arguments
   * @param onFulfilled - Callback that receives spread arguments
   * @returns Promise for callback result
   */
  spread<U>(onFulfilled: (...values: T extends any[] ? T : [T]) => U | Promise<U>): Promise<U>;
}

Object/Key Operations

// Import from when/keys module
import { all as keysAll, map as keysMap, settle as keysSettle } from "when/keys";

/**
 * Resolve all properties of an object
 * @param object - Object with promise or value properties
 * @returns Promise for object with resolved properties
 */
function keysAll<T extends Record<string, any>>(
  object: { [K in keyof T]: T[K] | Promise<T[K]> }
): Promise<T>;

/**
 * Map over object properties with promise-aware function
 * @param object - Object to map over
 * @param mapFunc - Mapping function for values
 * @returns Promise for object with mapped values
 */
function keysMap<T, U>(
  object: Record<string, T | Promise<T>>,
  mapFunc: (value: T, key: string) => U | Promise<U>
): Promise<Record<string, U>>;

/**
 * Settle all properties of an object
 * @param object - Object with promise or value properties
 * @returns Promise for object with settlement descriptors
 */
function keysSettle<T extends Record<string, any>>(
  object: { [K in keyof T]: T[K] | Promise<T[K]> }
): Promise<{ [K in keyof T]: SettleDescriptor<T[K]> }>;

Task Flow Control

Parallel Execution

/**
 * Run array of tasks in parallel with same arguments
 * @param tasks - Array of task functions
 * @param args - Arguments to pass to all tasks
 * @returns Promise for array of task results
 */
function parallel<T extends any[], U>(
  tasks: ((...args: T) => U | Promise<U>)[],
  ...args: T
): Promise<U[]>;

Sequential Execution

/**
 * Run array of tasks in sequence with same arguments
 * @param tasks - Array of task functions  
 * @param args - Arguments to pass to all tasks
 * @returns Promise for array of task results
 */
function sequence<T extends any[], U>(
  tasks: ((...args: T) => U | Promise<U>)[],
  ...args: T
): Promise<U[]>;

Pipeline Execution

/**
 * Run tasks in pipeline where each receives result of previous
 * @param tasks - Array of task functions
 * @param initialArgs - Arguments for first task
 * @returns Promise for final task result
 */
function pipeline<T extends any[], U>(
  tasks: [(...args: T) => any, ...((arg: any) => any)[]],
  ...initialArgs: T
): Promise<U>;

Polling and Monitoring

interface CancelablePromise<T> extends Promise<T> {
  /** Cancel the polling operation */
  cancel(): void;
}

/**
 * Poll a task until condition is met or cancelled
 * @param task - Task function to poll
 * @param interval - Polling interval in milliseconds  
 * @param verifier - Optional condition verifier
 * @returns Cancelable promise for polling result
 */
function poll<T>(
  task: () => T | Promise<T>,
  interval: number,
  verifier?: (result: T) => boolean | Promise<boolean>
): CancelablePromise<T>;

Callback Integration

Callback Lifting

// Import from when/callbacks module
import { lift, apply, call, promisify } from "when/callbacks";

/**
 * Lift callback-style function to promise-returning function
 * @param callbackFunc - Function expecting callback(err, result)
 * @returns Promise-returning version of function
 */
function lift<TArgs extends any[], TResult>(
  callbackFunc: (...args: [...TArgs, (err: any, result?: TResult) => void]) => void
): (...args: TArgs) => Promise<TResult>;

/**
 * Apply callback-style function with args array and return promise
 * @param callbackFunc - Function expecting callback(err, result)
 * @param args - Arguments array for function
 * @returns Promise for function result
 */
function apply<TArgs extends any[], TResult>(
  callbackFunc: (...args: [...TArgs, (err: any, result?: TResult) => void]) => void,
  args: TArgs
): Promise<TResult>;

/**
 * Call callback-style function with individual arguments
 * @param callbackFunc - Function expecting callback(err, result)
 * @param args - Arguments for function
 * @returns Promise for function result
 */
function call<TArgs extends any[], TResult>(
  callbackFunc: (...args: [...TArgs, (err: any, result?: TResult) => void]) => void,
  ...args: TArgs
): Promise<TResult>;

Node.js Integration

// Import from when/node module
import { lift, apply, call, createCallback, bindCallback, liftCallback } from "when/node";

/**
 * Lift Node.js-style callback function to promise-returning function
 * @param nodeFunc - Function expecting Node-style callback(err, result)
 * @returns Promise-returning version of function
 */
function lift<TArgs extends any[], TResult>(
  nodeFunc: (...args: [...TArgs, (err: any, result?: TResult) => void]) => void
): (...args: TArgs) => Promise<TResult>;

/**
 * Apply Node.js-style function with args array and return promise
 * @param nodeFunc - Function expecting Node-style callback(err, result)
 * @param args - Arguments array for function
 * @returns Promise for function result
 */
function apply<TArgs extends any[], TResult>(
  nodeFunc: (...args: [...TArgs, (err: any, result?: TResult) => void]) => void,
  args: TArgs
): Promise<TResult>;

/**
 * Call Node.js-style function with individual arguments and return promise
 * @param nodeFunc - Function expecting Node-style callback(err, result)
 * @param args - Arguments for function
 * @returns Promise for function result
 */
function call<TArgs extends any[], TResult>(
  nodeFunc: (...args: [...TArgs, (err: any, result?: TResult) => void]) => void,
  ...args: TArgs
): Promise<TResult>;

/**
 * Create a Node.js-style callback from a resolver
 * @param resolver - Promise resolver with resolve/reject methods
 * @returns Node-style callback function
 */
function createCallback(resolver: {
  resolve: (value: any) => void;
  reject: (reason: any) => void;
}): (err: any, value?: any) => void;

/**
 * Bind a Node.js-style callback to a promise
 * @param promise - Promise to bind callback to
 * @param callback - Node-style callback function
 * @returns Promise with same state as input promise
 */
function bindCallback<T>(
  promise: Promise<T>,
  callback: (err: any, value?: T) => void
): Promise<T>;

/**
 * Lift a Node.js-style callback to accept promises
 * @param callback - Node-style callback to lift
 * @returns Function that accepts a promise and calls callback on resolution
 */
function liftCallback(
  callback: (err: any, value?: any) => void
): (promise: Promise<any>) => Promise<any>;

Utilities

Type Guards

/**
 * Check if value is thenable (promise-like)
 * @param x - Value to test
 * @returns True if value has then method
 */
function isPromiseLike(x: any): x is Promise<any>;

Error Types

/**
 * Error thrown when promise times out
 */
class TimeoutError extends Error {
  constructor(message?: string);
}

Module Exports

When.js provides multiple ways to access its functionality:

// Main module exports
import when from "when";
import * as callbacks from "when/callbacks";
import * as fn from "when/function";  
import * as keys from "when/keys";
import * as node from "when/node";
import parallel from "when/parallel";
import sequence from "when/sequence";
import pipeline from "when/pipeline";
import poll from "when/poll";
import delay from "when/delay";
import timeout from "when/timeout";
import guard from "when/guard";
import * as generator from "when/generator";

// ES6 Promise shim
import Promise from "when/es6-shim/Promise";

Common Patterns

Promise Chaining

when(getData())
  .then(processData)
  .then(saveData)
  .catch(handleError)
  .finally(cleanup);

Error Propagation

when.resolve(value)
  .then(step1)
  .catch(recoverFromStep1Error)
  .then(step2)
  .catch(handleFinalError);

Array Processing

const urls = ['url1', 'url2', 'url3'];
when.map(urls, fetchUrl)
  .then(results => when.all(results.map(processResponse)))
  .then(processedData => console.log('All done:', processedData));

Conditional Processing

when(condition)
  .then(result => result ? doSomething() : doSomethingElse())
  .then(handleResult);

Execution Guards

// Import from when/guard module
import guard from "when/guard";

/**
 * Create guarded version of function that can only execute when condition allows
 * @param condition - Function that returns promise for condition check
 * @param f - Function to guard
 * @returns Guarded version of function
 */
function guard<TArgs extends any[], TResult>(
  condition: () => Promise<any>,
  f: (...args: TArgs) => TResult | Promise<TResult>
): (...args: TArgs) => Promise<TResult>;

/**
 * Create guard that limits concurrent executions to N
 * @param count - Maximum number of concurrent executions
 * @returns Guard condition function
 */
function guardN(count: number): () => Promise<any>;

Generator Support

// Import from when/generator module
import { lift as liftGenerator, call as callGenerator, apply as applyGenerator } from "when/generator";

/**
 * Lift a generator function to work with promises and yield
 * @param generator - Generator function to lift
 * @returns Promise-aware generator function
 */
function liftGenerator<TArgs extends any[], TResult>(
  generator: (...args: TArgs) => Generator<any, TResult, any>
): (...args: TArgs) => Promise<TResult>;

/**
 * Call generator immediately as promise-aware coroutine
 * @param generator - Generator function to call
 * @param args - Arguments to pass to generator
 * @returns Promise for generator result
 */
function callGenerator<TArgs extends any[], TResult>(
  generator: (...args: TArgs) => Generator<any, TResult, any>,
  ...args: TArgs
): Promise<TResult>;

/**
 * Apply generator with args array as promise-aware coroutine
 * @param generator - Generator function to apply
 * @param args - Arguments array for generator
 * @returns Promise for generator result
 */
function applyGenerator<TArgs extends any[], TResult>(
  generator: (...args: TArgs) => Generator<any, TResult, any>,
  args: TArgs
): Promise<TResult>;

Deprecated Modules

Standalone Delay (Deprecated)

// Import from when/delay (deprecated - use promise.delay() instead)
import delay from "when/delay";

/**
 * Create promise that resolves after delay
 * @deprecated Use when(value).delay(ms) instead
 * @param ms - Delay in milliseconds
 * @param value - Value to resolve with after delay
 * @returns Promise that resolves after delay
 */
function delay<T>(ms: number, value?: T): Promise<T>;

Standalone Timeout (Deprecated)

// Import from when/timeout (deprecated - use promise.timeout() instead)
import timeout from "when/timeout";

/**
 * Create promise that times out
 * @deprecated Use when(promise).timeout(ms) instead
 * @param ms - Timeout in milliseconds
 * @param promise - Promise to add timeout to
 * @returns Promise that rejects if timeout exceeded
 */
function timeout<T>(ms: number, promise: Promise<T>): Promise<T>;

Unfold Utilities (Deprecated)

// Import from when/unfold (deprecated - use cujojs/most streams instead)
import unfold from "when/unfold";
import { unfold as unfoldList } from "when/unfold/list";

/**
 * Generate promise stream from generator function
 * @deprecated Use cujojs/most streams instead
 * @param generator - Function that generates values
 * @param condition - Condition function to stop generation
 * @param seed - Initial seed value
 * @returns Promise for generated sequence
 */
function unfold<T, U>(
  generator: (seed: T) => U | Promise<U>,
  condition: (value: U, seed: T) => boolean | Promise<boolean>,
  seed: T
): Promise<U[]>;