Skip to content

About AsyncSignal

AsyncSignal is a lightweight async-control library with two core modules — asyncSignal and AsyncLoader — that target two common problems: async coordination and data loading. Both are built on a reusable async signal and interoperate seamlessly with native APIs like AbortController and fetch.

The two modules

asyncSignal: a reusable signal

Like Promise.withResolvers(), but resettable and reusable, with manual resolve / reject, status queries (isPending / isFulfilled / isRejected), timeout waits, constraints (until), auto-reset, and two-way integration with AbortController.

Suited for "wait for the same async event multiple times", "timeout control", "manually trigger completion":

typescript
import { asyncSignal } from "asyncsignal";

const signal = asyncSignal<string>();
// Multiple consumers wait on the same signal
signal().then((v) => console.log("got", v));
// Trigger completion at some point
signal.resolve("done");
// Reuse: reset and wait again
signal.reset();

See the asyncSignal features.

AsyncLoader: a data loader

Encapsulates loading + caching + abort + timeout + retry + multiplexing + error fallback + multi-loader. The underlying loader receives a merged abort signal (manual abort + timeout) via args.abortSignal, which can be passed directly to fetch:

typescript
import { AsyncLoader } from "asyncsignal/loader";

const loader = new AsyncLoader(
    async (args) => (await fetch("/api/data", { signal: args.abortSignal })).json(),
    { cache: 60_000, timeout: 5_000, retry: 2 }
);
const data = await loader.get();

Supports multi-loader orchestration: fallback failover (auto-switch on primary failure) and combine multi-source merge (concurrent loads aggregated). See the AsyncLoader features.

How they relate

AsyncLoader is built on top of asyncSignal — it uses an asyncSignal internally to carry the load result, so it naturally inherits the signal's status semantics (abortable, observable pending / fulfilled / rejected). The relationship:

asyncSignalAsyncLoader
RoleGeneral async coordination primitiveData loader (load / cache / retry / multi-source)
Reusereset() to wait againget() / refresh() manage it
Typical useEvent wait, timeout control, manual completionAPI requests, data caching, failover/merge

Package entry points

  • Main entry asyncsignal: only the asyncSignal signal part (lighter)
  • Subpath asyncsignal/loader: everything (asyncSignal + AsyncLoader)

Which one to use

  • Only need to wait for an async event / timeout / manual completion → use asyncSignal
  • Need to load data + cache + retry + abort + multi-source → use AsyncLoader
  • They compose: AsyncLoader already uses asyncSignal internally; you can also use asyncSignal alone for lower-level coordination.

Installation

bash
bun add asyncsignal
# or npm i asyncsignal / pnpm add asyncsignal / yarn add asyncsignal

Continue with Installation and Quick Start.

Released under the MIT License.