mrkeyoor.com_
Sat 08 Aug 21:00 UTC
npmUtilsupdated 08 Aug 2026

@react-dnd/asap

@react-dnd/asap is a tiny high-priority callback queue extracted into the React DnD monorepo. Calling asap(fn) postpones fn until after the current synchronous work, then drains queued tasks in first-in, first-out order before yielding to browser rendering or other I/O. It uses MutationObserver where available and a timer-plus-interval fallback elsewhere, and it catches task errors so later queued callbacks can continue before the error is rethrown on a lower-priority turn. This is scheduling infrastructure, not a React hook or drag-and-drop API.

Verdict

Do not add @react-dnd/asap to a new application just to postpone work; use queueMicrotask, requestAnimationFrame, or a yielding scheduler according to the job. Keep it where an existing React DnD dependency or exact queue semantics make replacement riskier than its stale packaging and documentation.

API stability4/5The installed 5.0.2 surface is very small: asap, AsapQueue, TaskFactory, and the Task and TaskFn types. Its FIFO drain and delayed error rethrow behavior come from the older asap design and have changed little. Stability is weakened by packaging drift: npm 5.0.2 is ESM-only at the root, while the current monorepo package file describes newer CommonJS and ESM export conditions that have not been published under a later version.
Docs2/5The README is unusually detailed about starvation, animation, recursive queues, task ordering, MutationObserver scheduling, timer fallbacks, and exception handling. Unfortunately, it is largely the original asap README rather than accurate package documentation. It instructs readers to require('asap'), describes an asap/raw entry that this package does not export, cites Node 0.10 and long-obsolete browsers, and does not show the actual named ESM import. Current source declarations are required to use 5.0.2 confidently.
Maintenance2/5The containing React DnD repository is not archived and was pushed in July 2025, but that top-level activity overstates attention to this utility. npm 5.0.2 was published in April 2022, and GitHub's path-specific commit history shows the last changes to packages/util-asap in January 2023, mostly build and workspace updates. The repository's 475 open issues and pull requests are project-wide, so they do not provide a useful package support signal.
Ecosystem3/5The package recorded 4,589,145 npm downloads in the measured week and inherits visibility from the React DnD monorepo, which has 21,628 stars. Those numbers are mainly evidence of transitive installation, not a standalone community: the API has no plugin layer, dedicated issue tracker, or current examples of its own. Standards such as queueMicrotask and requestAnimationFrame also cover most new application use cases without an ecosystem dependency.

Use it if

  • You maintain code that already receives @react-dnd/asap transitively and need its exact queue ordering or error behavior
  • You need a callback queue that drains newly added tasks in the same flush before yielding to rendering or I/O
  • You target old browser-style environments where the package's MutationObserver and timer fallback is part of an established compatibility contract
  • You are maintaining React DnD internals or another package built around this specific ASAP implementation
Skip it if

Setup reality

npm install @react-dnd/asap adds no runtime or peer dependencies and performs no native build, code generation, credential lookup, or configuration. Version 5.0.2 is an ES module package and exposes named exports from its root, so use import {asap} from '@react-dnd/asap'. The npm tarball does not publish a CommonJS export map, even though the monorepo's newer unpublished package.json contains separate require and import targets. That means documentation read from the current main branch can describe packaging that the installed 5.0.2 tarball does not have. The included README is older still: it says to require('asap') and documents asap/raw, but neither is an @react-dnd/asap 5.0.2 export. The public TypeScript declarations are the safer API reference. Scheduling has sharp edges. The queue drains completely, including callbacks added during a flush, so recursive scheduling can create an infinite event-loop turn without overflowing the stack. There is no cancel function, Promise result, delay, or backpressure. A thrown callback error is captured, queued callbacks continue, and the error is rethrown later by a timer; local try/catch inside the original caller cannot catch that asynchronous exception. In rendering code, use requestAnimationFrame when work must align with paint, and use a timer or another yielding scheduler when long work must allow input or I/O between chunks.

Patterns

Run a callback after synchronous workdefer-callback

import {asap} from '@react-dnd/asap';

console.log('before');
asap(() => console.log('deferred'));
console.log('after');
// before, after, deferred

The callback never runs inline, but it is scheduled ahead of rendering and most I/O once the current work returns.

Queue callbacks in first-in, first-out orderpreserve-fifo-order

import {asap} from '@react-dnd/asap';

asap(() => console.log('first'));
asap(() => console.log('second'));
asap(() => console.log('third'));

A single shared module queue preserves insertion order and drains all three tasks in the same flush.

Append work while the queue is flushingenqueue-during-flush

asap(() => {
  console.log('outer');
  asap(() => console.log('nested'));
});
asap(() => console.log('sibling'));
// outer, sibling, nested

New tasks join the current queue and run before the scheduler yields. Unbounded recursive enqueueing can starve the event loop indefinitely.

Make a cached callback consistently asynchronousavoid-zalgo-callback

function loadCached(key: string, done: (value: string) => void) {
  const value = cache.get(key);
  if (value !== undefined) {
    asap(() => done(value));
    return;
  }
  readValue(key, done);
}

Deferring the cache-hit branch avoids an API that sometimes calls done before the caller returns and sometimes calls it later.

Handle expected failures inside the taskcapture-callback-error

asap(() => {
  try {
    updateIndex();
  } catch (error) {
    reportFailure(error);
  }
});

Uncaught task errors are rethrown on a later timer turn. Catch errors inside the callback when they are expected and recoverable.

Notify observers after a synchronous state changeschedule-state-notification

const listeners = new Set<() => void>();

function setState(next: State) {
  state = next;
  for (const listener of listeners)
    asap(listener);
}

All listeners run asynchronously in registration order. This queue does not batch duplicate callbacks or isolate a slow listener.

Build an independent ASAP queuecreate-private-queue

import {AsapQueue, TaskFactory} from '@react-dnd/asap';

const queue = new AsapQueue();
const factory = new TaskFactory(queue.registerPendingError);

queue.enqueueTask(factory.create(() => {
  console.log('private queue');
}));

The root asap function uses a module-global queue. Constructing these exported classes isolates task order, but ties code to lower-level internals.

Wrap scheduling in a Promise for testswait-for-asap-task

function nextAsapTurn(): Promise<void> {
  return new Promise(resolve => asap(resolve));
}

asap(() => updateModel());
await nextAsapTurn();
expect(model.updated).toBe(true);

asap itself returns void. A Promise wrapper gives tests something to await, but failures thrown by another task are still rethrown separately.

Emit after subscribers can attachdefer-event-emission

import {EventEmitter} from 'node:events';

function createJob() {
  const job = new EventEmitter();
  asap(() => job.emit('ready'));
  return job;
}

createJob().on('ready', () => console.log('ready'));

Deferral lets the caller register its listener before emission. Use queueMicrotask directly in new code unless this package is already required.

Use a rendering scheduler for visual workyield-to-rendering

requestAnimationFrame(() => {
  updateCanvas();
});

This intentionally does not call asap. The package README warns that its fully drained high-priority queue can delay reflow, repaint, and input.

Alternatives

PackageRegistryPick it when
queue-microtasknpmChoose it when you need the standard queueMicrotask API plus a fallback for runtimes that do not provide it
asapnpmChoose it only when maintaining software that explicitly depends on the original package and its documented raw subpath
p-immediatenpmChoose it when Promise-based deferral to an immediate task is more useful than a callback queue that drains before I/O