Skip to content

whilst

whilst repeatedly executes an async task as long as a test condition returns true. The library also exports until, doWhilst, and doUntil as related loop constructs.

Best for conditional loops Use whilst when you need to poll until a condition is met, retry until success, or loop while a resource is available.

Root package:

import { whilst, until, doWhilst, doUntil } from "@vgerbot/async";

Module subpath:

import { whilst, until, doWhilst, doUntil } from "@vgerbot/async/control-flow";

Leaf subpath:

import { whilst } from "@vgerbot/async/control-flow/whilst";
import { whilst } from "@vgerbot/async";
let count = 0;
const handle = whilst(
async () => count < 5,
async (token) => {
await token.sleep(100);
count++;
},
);
await handle;
console.log(count); // 5
  • whilst: Check condition first, then run task. Loop while condition is true.
  • until: Check condition first, then run task. Loop until condition is true (opposite of whilst).
  • doWhilst: Run task first, then check condition. Loop while condition is true.
  • doUntil: Run task first, then check condition. Loop until condition is true.
type WhilstTest = (token: CancellableToken) => boolean | Promise<boolean>;
type WhilstIteratee = (token: CancellableToken) => void | Promise<void>;
function whilst(
test: WhilstTest,
iteratee: WhilstIteratee,
options?: CancellableOptions,
): CancellableHandle<void>;
function until(
test: WhilstTest,
iteratee: WhilstIteratee,
options?: CancellableOptions,
): CancellableHandle<void>;
function doWhilst(
iteratee: WhilstIteratee,
test: WhilstTest,
options?: CancellableOptions,
): CancellableHandle<void>;
function doUntil(
iteratee: WhilstIteratee,
test: WhilstTest,
options?: CancellableOptions,
): CancellableHandle<void>;
Parameter Type Default Description
test (token) => boolean | Promise<boolean> Condition evaluated before (or after) each iteration. Receives a CancellableToken. Can return a boolean or a Promise that resolves to a boolean.
iteratee (token) => void | Promise<void> Async function executed on each iteration. Receives a CancellableToken.
options CancellableOptions undefined Cancellable configuration options.

Returns a CancellableHandle<void> that resolves when the loop completes.

const handle = whilst(test, iteratee);
await handle;
handle.cancel("No longer needed");
handle.isCancelled();
handle.signal;
  1. Call test(). If it resolves to false, stop.
  2. Call iteratee(token).
  3. Repeat from step 1.
  1. Call test(). If it resolves to true, stop.
  2. Call iteratee(token).
  3. Repeat from step 1.
  1. Call iteratee(token).
  2. Call test(). If it resolves to false, stop.
  3. Repeat from step 1.
  1. Call iteratee(token).
  2. Call test(). If it resolves to true, stop.
  3. Repeat from step 1.
// Polling with whilst
import { whilst } from "@vgerbot/async";
const handle = whilst(
async () => {
const status = await fetch("/api/job/status").then((r) => r.json());
return status.state !== "completed";
},
async (token) => {
await token.sleep(1000); // Poll every second
},
{ name: "jobPolling" },
);
await handle;
console.log("Job completed");

If either test or iteratee rejects, the loop stops and the handle rejects with that error.

try {
await whilst(
async () => true,
async () => { throw new Error("iteratee failed"); },
);
} catch (error) {
console.log("Loop failed:", error);
}

The loop checks for cancellation between iterations. Calling cancel() on the handle causes the next iteration check to throw a CancelError.

const handle = whilst(
async () => true,
async (token) => { await token.sleep(1000); },
{ name: "infinitePoll" },
);
setTimeout(() => handle.cancel("User navigated away"), 5000);
try {
await handle;
} catch (error) {
if (error instanceof CancelError) {
console.log("Loop was cancelled");
}
}

The iteratee returns Promise<void> — it does not accumulate results. Use reduce or transform if you need to collect values across iterations.

// Collecting results with transform instead
import { transform } from "@vgerbot/async";
const results = await transform(
Array.from({ length: 5 }, (_, i) => i),
async (acc, i, token) => {
await token.sleep(10);
acc.push(i * 2);
},
[] as number[],
);
  • forever runs a task indefinitely until cancelled.
  • times repeats a task a fixed number of times.
  • retry retries a task on failure.
  • reduce reduces a collection sequentially.