npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

defer-queue-js

v1.2.1

Published

Tiny defer queue utility for scheduling sync/async cleanup callbacks in JS/TS

Readme

defer-queue-js

A tiny JavaScript/TypeScript utility for scheduling cleanup or teardown callbacks to run later — useful for running tasks at the end of a lifecycle step (for example: component unmount, request teardown, or end of a worker task).

This repository exposes a single class DeferQueue that collects two kinds of deferred callbacks and runs them when you call defer().

Features

  • Append synchronous or asynchronous deferred callbacks
  • Run all async callbacks in parallel and then run queued sync callbacks in order
  • Lightweight and zero-dependency (implemented in TypeScript)

Installation

Install from npm (example):

npm install defer-queue-js
# or
pnpm add defer-queue-js
yarn add defer-queue-js

If you prefer to use the source directly, you can still copy index.ts into your project.

If you use TypeScript, the exported DeferQueue class and DeferredCallback type are available from the package.

Quick example

import DeferQueue from 'defer-queue-js';

const queue = new DeferQueue('my-queue');

// add an async cleanup
queue.appendAsync(async () => {
  await someAsyncCleanup();
});

// add a sync (fast) cleanup
queue.appendSync(() => {
  doFastCleanup();
});

// later, run all deferred callbacks
await queue.defer();

API

  • type DeferredCallback = () => Promise | void

  • class DeferQueue

    • constructor(name?: string)

      • name: optional name used when logging errors
    • appendSync(deferredCallback: DeferredCallback): void

      • Pushes a callback onto the synchronous queue. These callbacks are intended to be run in FIFO order.
    • appendAsync(deferredCallback: DeferredCallback): void

      • Pushes a callback onto the asynchronous queue. These callbacks will be executed in parallel when defer() is called.
    • defer(): Promise

      • Executes all asynchronous callbacks in parallel (each awaited and errors are caught and logged). At the same time it runs through the synchronous queue by shifting items until none remain. The method resolves once all work is complete.

Behavior details and notes

  • Async callbacks: each function added via appendAsync is invoked and awaited. If a callback throws or rejects, the error is caught and logged with console.error including the queue name.

  • Sync callbacks: functions added via appendSync are stored in an internal array and processed with shift() inside defer() until the array is empty. The intention is to process sync callbacks in order.

  • Error handling: defer() traps errors from both kinds of callbacks and logs them. It does not rethrow, so callers should not expect an exception even if callbacks fail.

When to use sync vs async

Use appendSync when the callbacks have ordering dependencies — for example resources that must be torn down in the opposite order they were started. A typical pattern:

  • open DB connection
  • start HTTP server (which depends on DB)

On shutdown you want to stop accepting requests before you close the DB. To express that ordering use the sync queue so callbacks run in FIFO order and are awaited one-by-one:

import DeferQueue from 'defer-queue-js';

const q = new DeferQueue('server-shutdown');

// start DB first
startDatabase();
q.appendSync(async () => {
	// on shutdown: close DB after server is stopped
	await db.close();
});

// then start server
startServer();
q.appendSync(async () => {
	// on shutdown: stop server first
	await server.stop();
});

// later on shutdown
await q.defer();

Because appendSync callbacks are shifted and awaited sequentially, you can rely on the order to express dependencies.

Use appendAsync for completely independent work that can run in parallel and doesn't depend on ordering — e.g. sending telemetry, clearing caches, or deleting temporary files. These run concurrently when defer() is called.

q.appendAsync(async () => {
	await sendTelemetry('shutdown');
});

q.appendAsync(() => {
	cleanupTempFiles();
});

Mixing both is supported: async callbacks run in parallel and the sync queue is processed (in order) as part of the overall defer() call.

License

This project contains no license file in the repository. Add a LICENSE if you want to publish the package.

Changelog

  • 2025-10-17: README added with API, examples and a suggested bug fix.