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 🙏

© 2024 – Pkg Stats / Ryan Hefner

promise-callbacks

v3.8.2

Published

Utilities to help convert a callback-using codebase to promises.

Downloads

81,043

Readme

promise-callbacks

This package helps you work with a codebase that uses promises instead of callbacks in most-but-not-all places. It differs from most other callback-to-promise libraries out there by preferring a deferred variant of a Promise with a Node callback-compliant defer method. As such, it is most different in that it focuses on interoperating with callbacks at the call site.

It also uses native promises not Bluebird etc.

This is because it's 2017, and this package assumes that you'll convert all your own code to use native promises (especially now that recent versions of Chrome and Node 7.6.0 natively support async/await) and the API calls left over will be 3rd-party libraries that you really don't want to patch, due to not having access to library classes and/or the general hackiness of monkey-patching (just try to trace this).

Hopefully these 3rd-party libraries will get their acts together in the relatively near future. In the meantime, there's promise-callbacks to keep it simple.

Installation

npm install promise-callbacks

or

npm install promise-callbacks --save

The minimum requirement is a native Promise implementation, though you'll get the most out of this if you're using Chrome minus 2 or Node 7.6.0 or higher for async/await.

Usage

Converting a callback to a promise

const { deferred } = require('promise-callbacks');

function respondWithDelay(done) {
  setTimeout(() => done(null, 'hi'), 2000);
}

async function foo() {
  const promise = deferred();
  respondWithDelay(promise.defer());
  console.log(await promise);
}

What happened there is that promise.defer() took the result of respondWithDelay, as a callback, and resolved/rejected the associated Promise.

It's also possible to achieve the above more succinctly using the callAsync function, as follows:

const { callAsync } = require('promise-callbacks');

async function foo() {
  console.log(await callAsync(respondWithDelay));
}

Variadic arguments

To support callbacks that provide several values, you have two options: as an array - where you can destructure into your own variables, or as an object, with a similar outcome.

const { deferred } = require('promise-callbacks');

function manyValues(done) {
  setTimeout(() => {
    done(null, 'several', 'values', 'here');
  }, 2000);
}

async function asArray() {
  const promise = deferred({ variadic: true });
  respondWithDelay(promise.defer());
  const [first, second, third] = await promise;
  console.log(`${first} ${second} ${third}`);
}

async function asObject() {
  const promise = deferred({ variadic: ['first', 'second', 'third'] });
  respondWithDelay(promise.defer());
  const { first, second, third } = await promise;
  console.log(`${first} ${second} ${third}`);
}

Converting a callback API to a promise API

The promisify function is based off of Node 8's util.promisify. It works on versions of Node prior to 8, and has special support for callbacks with multiple values, and has utilities to create a copy of an object with promise-returning methods.

For a function

const { promisify } = require('promise-callbacks');

function respondWithDelay(done) {
  setTimeout(() => done(null, 'hi'), 2000);
}

const respondWithDelayPromised = promisify(respondWithDelay);

async function foo() {
  console.log(await respondWithDelayPromised());
}

Variadic callbacks

Much like deferred, you can receive multiple callback arguments by passing the variadic option to promisify. This also works with promisify.methods and promisify.all.

const { promisify } = require('promise-callbacks');

function respondWithDelay(done) {
  setTimeout(() => done(null, 3, 2, 1, 4), 2000);
}

const respondWithDelayPromised = promisify(respondWithDelay, { variadic: true });

async function foo() {
  console.log(await respondWithDelayPromised());
  // => [3, 2, 1, 4]
}

For an object

const { promisify } = require('promise-callbacks');
const fs = require('fs');

// Note that readFile and writeFile are internally bound to fs, so they can interact with the
// original context object as they expect.
const { readFile, writeFile } = promisify.methods(fs, ['readFile', 'writeFile']);

readFile('input')
  .then((content) => writeFile('output', content))
  .catch((err) => console.error('err', err));

// If you just care about one method, a less verbose option you can use is promisify.method:
const readFileAsync = promisify.method(fs, 'readFile');

readFileAsync('input')
  .then((content) => writeFile('output', content))
  .catch((err) => console.error('err', err));

// If you know all the methods of the object are asynchronous, use promisify.all:
const api = {
  respondWithDelay,
};

const promiseAPI = promisify.all(api);

async function foo() {
  console.log(await promiseAPI.respondWithDelay());
}

Converting a promise to a callback

const { asCallback } = require('promise-callbacks');

asCallback(Promise.resolve(true), (err, res) => {
  console.log(res); // true
});

Straightforward. Or, if you don't mind just a little bit of monkey-patching:

const { patchPromise } = require('promise-callbacks');

// Call this once, when your application starts up,
// to add `asCallback` to `Promise.prototype`, as
// well as several utility functions to `Promise`
// itself (see below).
patchPromise();

// Thereafter:
Promise.resolve(true).asCallback((err, res) => {
  console.log(res); // true
});

Creating a Defer object

const { defer } = require('promise-callbacks');

const def = defer();
// => Hello, world!
def.promise.then((message) => console.log(message));
def.resolve('Hello, world!');

Promise utilities

These utilities are exposed if patchPromise is invoked. They are also accessible on the promise-callbacks module itself.

Promise.delay(timeout)

Returns a promise that will resolve after the specified timeout.

Promise.immediate()

Returns a promise that will resolve after the event loop has processed - analogous to setImmediate.

Promise.nextTick()

Returns a promise that will resolve after the next process tick - analogous to process.nextTick.

Promise.withTimeout(promise, timeout, [message])

Returns a promise that will reject after the specified timeout, unless the given promise resolves or rejects before that timeout.

Promise.objectAll(object)

Resolves the values of the provided object, similar to Promise.all. Useful for Promise.all invocations that have grown so large in size that it's difficult to easily understand which expressions are associated with which bindings.

const { status, assignment } = await Promise.objectAll({
  status: getStatus(),

  sendResult: send(notificationObject),

  assignment: assignReviewer(),
});

Real-world example

example/app.js demonstrate these APIs' use in the context of a web server. Do yarn run example to start it.

Shout-outs

asCallback is inspired by Bluebird.