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":
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:
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:
asyncSignal | AsyncLoader | |
|---|---|---|
| Role | General async coordination primitive | Data loader (load / cache / retry / multi-source) |
| Reuse | reset() to wait again | get() / refresh() manage it |
| Typical use | Event wait, timeout control, manual completion | API requests, data caching, failover/merge |
Package entry points
- Main entry
asyncsignal: only theasyncSignalsignal 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:
AsyncLoaderalready usesasyncSignalinternally; you can also useasyncSignalalone for lower-level coordination.
Installation
bun add asyncsignal
# or npm i asyncsignal / pnpm add asyncsignal / yarn add asyncsignalContinue with Installation and Quick Start.