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 🙏

© 2025 – Pkg Stats / Ryan Hefner

packoff

v2.0.0

Published

Promise based exponential backoff

Downloads

13

Readme

Packoff

Promise based backoff!

Packoff is a minimalist, promised based, exponential backoff lib. Given your current 'retry' attempt, it'll return a promise that you can await before attempting some operation again.

Installation

npm i packoff

Usage

The main backoff functions take an options object with the following arguments:

| Argument | Default | Description | | ---------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | currentAttempt | none (required) | The number of attempts tried so far. The higher this is, the longer the possible delay | | baseDelayTime | 1000 (1 sec) | This is the base amount of time (in milliseconds used to calculate the backoff delay.) | | jitter | true | With jitter, your backoff attempt delays will have a smoother curve. You normally want this. Read this for more info. | | cap | 20000 (20 sec) | This caps the max delay of your back off attempts. If you're going to repeatedly retry something over and over, you probably don't want your attempts to end up in the minute time frame... unless you do |

The simplest use case is when you have some async thing you want to try over and over until it works.

import { backoff } from 'packoff';
import riskyBusiness from './async-risky-business';

const tryToDoSomeWork = async () => {
  let isDone = false;
  let retries = 0;
  while (!isDone && retries < 10) {
    try {
      await riskyBusiness();
      console.log('success');
      isDone = true;
    } catch (e) {
      console.log('something went wrong, try again...');
      retries += 1;
      await backoff({ currentAttempt: retries, baseDelayTime: 1000 });
    }
  }
};

Optionally, if you want to setup some sort of base configuration, you can do that with setupBackoff.

import { setupBackoff } from 'packoff';
import riskyBusiness from './async-risky-business';

const myBackoff = setupBackoff({ baseDelayTime: 1500, jitter: false });

const tryToDoSomeWork = async () => {
  let isDone = false;
  let retries = 0;
  while (!isDone && retries < 10) {
    try {
      await riskyBusiness();
      console.log('success');
      isDone = true;
    } catch (e) {
      console.log('something went wrong, try again...');
      retries += 1;
      // Now you just need the attempt count;
      await myBackoff(retries);
    }
  }
};

The helper function tryUntilResolved is basically the above code wrapped up for you. It'll retry a given async function n (default: 10) times until the async function resolves successfully, backing off in between attempts. (It'll reject if all the attempts fail.)

import { tryUntilResolved } from 'packoff';
import riskyBusiness from './async-risky-business';

const riskyBusinessWithRetry = tryUntilResolved(riskyBusinessWithRetry, {
  baseDelayTime: 500,
  attemptLimit: 10,
});

const tryToDoSomeWork = async () => {
  riskyBusinessWithRetry(og, risky, args);
};

Lastly, when debugging or for logging, it may be useful to know how long your retry is going to wait. There are additional backoffWithMs and setupBackoffWithMs functions that return an array instead of a promise. The first element is the delay promise, the second is the ms until that promise resolves;

import { backoffWithMs } from 'packoff';

async function examp() {
  const [backoffPromise, ms] = backoffWithMs({
    baseDelayTime: 3000,
    currentAttempt: 2,
  });
  console.log(`Waiting ${ms} before continuing!`);
  await backoffPromise;
}