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

spaced-loop

v1.0.0

Published

Invoke a callback every so often, with an increasing delay upon failure and a max number of retries

Readme

spaced-loop

Standard loop where a user-defined callback is called every so often. If the callback throws an error, the delay between callback invocations is increased up to a maximum, and reset to its initial value upon a successful invocation. Useful when you don't want to spam an API with fetch requests, or wait a while after a failure before trying again.

Install

npm install spaced-loop

Usage

import SpacedLoop from 'spaced-loop';

const loop = new SpacedLoop({
  cb: (loop) => {
    console.log(
      `callback invoked! Throwing an error to increase the delay to ${loop.currentDelayMs + 2000}!`,
    );
    throw new Error('Something bad happened');
  },
  onError: (loop, error) => {
    console.error(error);
    console.log(
      `attempt ${loop.consecutiveErrors}/${loop.maxConsecutiveErrors} failed`,
    );
  },
  delayStepMs: 2000,
  maxDelayMs: 20000,
  maxConsecutiveErrors: 5,
});

await loop.body; 

console.log('loop finished running');

Constructor Parameters

The SpacedLoop constructor takes an object that can contain the following properties:

| Property | Type | Purpose | | -------- | ---- | ------- | | cb | function (loop: SpacedLoop): void | The callback that will run every iteration of the loop. If this callback throws an error, the loop will run the onError callback and add the delayStepMs onto the current delay time. If this callback is successful, the current delay time will be reset to its original value. This callback is passed a reference to the loop. | | onError | function (loop: SpacedLoop, error: unknown): void | The callback that will run in response to any errors thrown by the cb callback. You could use this to log errors, etc. This callback is passed a reference to the loop and the error that was thrown by the cb callback. | | onMaxErrors | function (loop: SpacedLoop, error: unknown): void | The callback that will run in response to the max consecutive errors being reached. You could use this to print a message after reaching the max errors, or take another course of action. This callback is passed a reference to the loop and the last error thrown by the cb callback. | | delayStepMs | number | The initial loop delay duration will be set to this value. Each time the loop encounters an error, this value will be added onto the loop delay duration. Defaults to 10 seconds. | | maxDelayMs | number | The maximum loop delay duration. Defaults to 60 seconds. | | maxConsecutiveErrors | number | So you can have the loop exit after a number of consecutive errors. E.g. if you want to retry a fetch request a maximum number of times before exiting, use this. Defaults to zero, which means there is no limit to the number of consecutive errors. | | ignoreRunTime | boolean | If this is set to false, the delay at the end of each iteration will be reduced to compensate for the time taken to execute the cb callback. So if the callback takes 500ms to execute and the current delay time is 600ms, the delay will only be 100ms, so the whole loop iteration will end up taking 600ms in total. If the callback takes 200ms or longer to execute and the current delay time is 200ms, the delay will be skipped entirely. Defaults to true. |

SpacedLoop Members

The returned loop (which is also passed into the cb and onError callbacks as in the above example) contains the following members:

| Property | Type | Purpose | | -------- | ---- | ------- | | body | Promise<void> | A promise that resolves once the loop has been exited. Await this in order to run some code once the loop has finished. | | currentDelayMs | number | Current minimum delay time until the next loop starts. If the callback takes a long time to execute, it is possible the time taken will exceed this value, hence current minimum delay time. | | consecutiveErrors | number | The number of consecutive errors thrown by loop iterations. Resets to zero when a loop iteration runs without throwing an error. Can be used to make logs, e.g. "retry 1/5", etc. | | maxConsecutiveErrors | number | The max number of consecutive errors before the loop exits automatically. If this is set to zero, then the loop will continue indefinitely, regardless of the number of errors thrown. Can be used to make logs, e.g. "retry 1/5", etc. | | exit | function (): void | This method causes the loop to exit after the current iteration has finished. That includes the wait time at the end of each iteration, so the promise stored in body will not resolve until the current wait period has elapsed. Since a reference to the loop is passed to all callbacks, the loop can be exited from within any of the callbacks by invoking this method. |