CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-when

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

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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[]>;
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/when@3.7.x
Publish Source
CLI
Badge
tessl/npm-when badge