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

@krhkt/atomic-promise

v1.1.2

Published

Promise wrapper that can be resolved or rejected directly

Readme

Atomic Promise JS

A thenable promise wrapper that can be resolved or rejected by directly invoking methods on the instance. It can be used interchangebly with the standard Promise instance.

An atomic promise doesn't need to wrap async code on instantiation, providing an interface that allows it to be connected to callbacks API more cleanly, by using .resolve() or .reject() at any point after its instantiation.

Usage

To create an atomic promise, just instantiate the class. The instance is nothing more than a wrapper of an internal promise that exposes .resolve() and .reject() as interface methods.

import { AtomicPromise } from '@krhkt/atomic-promise';

const atom = new AtomicPromise();

// add chain
atom.then(number => number + 1)
    .then(number => number + 2)
    .then(number => console.log('number:', number));

// resolving the wrapped promise
atom.resolve(3);
// ...
// > number: 6

await an AtomicPromise

It's possible to await an AtomicPromise since it's a thenable object.

const atom = new AtomicPromise();
setTimeout(() => atom.resolve(), 1000);

await atom;

console.log('timer done');

resolve() and reject() always return the AtomicPromise instance, so they can be used anywhere in the promise chain.

const atom = new AtomicPromise();
await atom
    .then((arg) => console.log('first: ', arg));
    .resolve(10)
    .then(() => console.log('second'));

// > first: 10
// > second

NOTE:
remember to only await an atomic promise if it's already resolved or if an async code will resolve/reject it later.

// DON'T DO THIS:
const atom = new AtomicPromise();
atom.then(() => console.log('all good'));

await atom; // will await forever

atom.resolve(); // will never be executed

Using AtomicPromise to simplify callback APIs

Instead of creating a lambda function wrapping a callback API, it's possible to simply use the instance in the closure.

const atom = new AtomicPromise();
setTimeout(() => atom.resolve(), 1000);

// for comparison, using the defaut Promise would result in wrapping
// the async code in a lambda, resulting in something like:
const promise = new Promise(
    (resolve, _) => setTimeout(resolve, 1000)
);

Example binding .resolve and .reject in a callback:

const atom = new AtomicPromise();
atom.then((rows) => console.log(rows))
    .catch((err) => console.log('error updating:', err));

// callback
sqlit3Db.run(
    'UPDATE tbl SET name = $name WHERE id = $id',
    { $id: 2, $name: 'bar' },
    (err, rows) => (err) ? atom.reject(err) : atom.resolve(rows)
);

It's also possible to plug an AtomicPromise directly to a callback by using .boundResolve.

const atom = new AtomicPromise();
setTimeout(atom.boundResolve, 1000);

console.log('timer running...');

await atom;
console.log('execution resumed');
// > timer running...
// > execution resumed

.boundResolve can also be used to unwrap the callback arguments. The API of Promise.resolve() only accepts a single argument, so the arguments of the callback will always be passed as an array, but it's possible to take advantage of the destructuring assignment to access the arguments more easily:

const atom = new AtomicPromise();
const asyncTask = (callback) => {
    setTimeout(() => {
        callback('all done!');
    }, 1);
};

asyncTask(atom.boundResolve); // supplying the callback

const [result] = await atom;
// result will contain the string 'all done!'

Ignoring arguments:

const atom = new AtomicPromise();
sqlit3Db.run(
    'select * from tbl where id=?', 1, 
    atom.boundResolve // callback
);

const [_, row] = await atom;

// retrieved row
console.log(row);

Another example:

const atom = new AtomicPromise();

sqlit3Db.run(
    'UPDATE tbl SET name = $name WHERE id = $id',
    { $id: 2, $name: 'bar' },
    atom.boundResolve, // callback
);

const [err, row] = await atom;
console.log(err, row);

// ALTERNATIVELY, the same can be achieved using .then()
atom.then(([err, row]) => {
    console.log(row);
});

NOTE:
The .boundResolve and .boundReject instance lambdas will always pipe multiple arguments of callbacks as an array to .then, .catch, and .finally callbacks.

If a callback only contains an error argument, it's possible to use a .boundError to make the error capturable in a try...catch statement.

const atom = new AtomicPromise();
fs.accept(filePath, fs.constants.F_OK, atom.boundError);
try {
    await atom;
    // if the callback didn't have any error argument, the promise is resolved

    // (... code to run if the callback had no error...)
} catch (err) {
    // if the error argument was present, the promise is rejected triggering an exception

    // (... code to run if the callback had an error...)
}

Chaining AtomicPromise and Promise

The instance can also be used to chain atomic and standard promises:

const atom = new AtomicPromise();

const promiseA = new Promise((resolve, _) => {
    setTimeout(() => resolve('promiseA resolved'), 1000);
});

const promiseB = new Promise((resolve, _) => {
    setTimeout(() => resolve('promiseB resolved'), 2000);
});

await promiseA
    .then((result) => console.log('1st:', result))
    .then(() => atom.resolve('atom resolve'))
    .then((result) => console.log('2nd:', result))
    .then(() => promiseB)
    .then((result) => console.log('3rd:', result));

// > 1st: promiseA resolved
// > 2nd: atom resolve
// > 3rd: promiseB resolved

Or, when resolving the atomic promise asynchronously:

const atom = new AtomicPromise();

const promiseA = new Promise((resolve, _) => {
    setTimeout(() => resolve('promiseA resolved'), 1000);
});

setTimeout(() => atom.resolve('atom resolved'), 2000);

const promiseB = new Promise((resolve, _) => {
    setTimeout(() => resolve('promiseB resolved'), 3000);
});

await promiseA
    .then((result) => console.log('1st:', result))
    .then(() => atom)
    .then((result) => console.log('2nd:', result))
    .then(() => promiseB)
    .then((result) => console.log('3rd:', result));

// > 1st: promiseA resolved
// > 2nd: atom resolved
// > 3rd: promiseB resolved

API

Constructor

AtomicPromise(): creates a new AtomicPromise object. The constructor doesn't accept any parameter.

Static methods

AtomicPromise.resolve(payload): simply creates a resolved AtomicPromise. Only use this method for class bound integrations. Prefer the standard Promise.resolve() if possible.

AtomicPromise.reject(payload): simply creates a rejected AtomicPromise. Only use this method for class bound integrations. Prefer the standard Promise.reject() if possible.

Instance properties

.id: returns an integer uniquely identifying the instance. It's a simple auto-increment number that wraps when it gets close to the MAX_SAFE_INTEGER.

isFulfilled: boolean, returns true if the promise is resolved or rejected, or false if the promise is pending.

isResolved: boolean, returns true if the promise is resolved, false otherwise.

isRejected: boolean, returns true if the promise is rejected, false otherwise.

.boundResolve: a lambda that is bound to the instance that can be used directly as a callback to resolve the promise.

.unwrappedResolve: same as .boundResolve, but if the callback has only one argument, there's no need to use the destructuring assignment.

.boundReject: a lambda that is bound to the instance that can be used directly as a callback to reject the promise.

.unwrappedReject: same as .boundReject, but if the callback has only one argument, there's no need to use the destructuring assignment.

.boundError: a lambda that will reject the promise if the first argument is a non falsy value, otherwise will resolve the promise successfully.

Instance methods

.resolve(): will resolve the underlying promise with the provided argument. Returns the AtomicPromise instance.

.reject(): will reject the underlying promise with the provided argument. Returns the AtomicPromise instance.

.then(): delegates the argument to the .then method of the underlying promise. Returns the AtomicPromise instance.

.catch(): delegates the argument to the .catch method of the underlying promise. Returns the AtomicPromise instance.

.finally(): delegates the argument to the .finally method of the underlying promise. Returns the AtomicPromise instance.

.asPromise(): returns the underlying promise. This method is useful to integrate with third party code that expects a standard promise instance.