Skip to content

tryEach

tryEach runs an array of async tasks sequentially, returning the result of the first successful task. If all tasks fail, it throws the last error.

Best for fallback chains Use tryEach when you have multiple strategies or endpoints to try, and you want the first one that works.

Root package:

import { tryEach } from "@vgerbot/async";

Module subpath:

import { tryEach } from "@vgerbot/async/control-flow";

Leaf subpath:

import { tryEach } from "@vgerbot/async/control-flow/tryEach";
import { tryEach } from "@vgerbot/async";
const handle = tryEach([
async (token) => {
const res = await token.wrap(fetch("https://api1.example.com/data"));
if (!res.ok) throw new Error("api1 unavailable");
return res.json();
},
async (token) => {
const res = await token.wrap(fetch("https://api2.example.com/data"));
if (!res.ok) throw new Error("api2 unavailable");
return res.json();
},
async (token) => {
const res = await token.wrap(fetch("https://api3.example.com/data"));
if (!res.ok) throw new Error("api3 unavailable");
return res.json();
},
]);
const data = await handle; // First successful response
  • Fallback endpoints: Try multiple API endpoints in priority order.
  • Alternative strategies: Attempt different approaches to solve a problem.
  • Graceful degradation: Try the best option first, falling back to less ideal alternatives.
  • Cancellable fallbacks: Cancel the entire chain from outside.
function tryEach<T>(
tasks: AsyncTask<T>[],
options?: CancellableOptions<T>,
): CancellableHandle<T>;
Parameter Type Default Description
tasks AsyncTask<T>[] Array of async tasks to try in order. Each receives a CancellableToken.
options CancellableOptions<T> undefined Cancellable configuration options.

Returns a CancellableHandle<T> that resolves to the first successful result, or rejects with the last error if all tasks fail.

const handle = tryEach(tasks);
const result = await handle;
handle.cancel("No longer needed");
handle.isCancelled();
handle.signal;

Tasks are executed one at a time in order. If a task succeeds, its result is returned immediately and remaining tasks are skipped. If a task fails, the error is stored and the next task is tried. If all tasks fail, the last error is thrown.

const handle = tryEach([
async () => { throw new Error("fail 1"); },
async () => { throw new Error("fail 2"); },
async () => "success",
]);
const result = await handle; // "success"

If the tasks array is empty, tryEach throws an error immediately.

If all tasks reject, the handle rejects with the last task’s error.

try {
await tryEach([
async () => { throw new Error("fail 1"); },
async () => { throw new Error("fail 2"); },
]);
} catch (error) {
console.log("All tasks failed:", error); // Error: fail 2
}

All tasks share a single CancellableToken. The loop checks for cancellation before each task.

const handle = tryEach(
[
async (token) => { await token.sleep(5000); return "slow"; },
async (token) => "fast fallback",
],
{ name: "fallbackChain" },
);
setTimeout(() => handle.cancel("User cancelled"), 100);

tryEach is generic over T. All tasks must return the same type.

const handle = tryEach([
async () => "text",
async () => "fallback text",
]);
const result = await handle; // string
  • any tries tasks concurrently and resolves with the first to fulfill.
  • retry retries the same task on failure.
  • series runs tasks sequentially, passing results forward.
  • race settles with the first task to complete.