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

tentative

v2.0.3

Published

Simple yet handy promises retry utility

Downloads

5

Readme

🌀 Tentative

A simple yet handy promises retry utility.

✨ Features

  • 🪶 Light & minimal with 0 dependencies.
  • 🛠️ Easily & highly customisable.
  • 🧬 Leverages proxies so that the output can be used as a drop-in replacement of the original function; its call is powered with a retry strategy.

🦾 Usage

The tentative package exports a single default function, here called tente, to retry a promise in case of failure using a custom strategy.

🤖 Syntax

tente(retryable)
tente(retryable, options)

⚙️ Parameters

  • retryable: The function returning a promise that will be retried on failure.
  • options (optional): An object to customise the retry behavior. It supports the following fields:
    • attempts (optional): Specifies the maximum number of retries and the delay between each retry. It can have the following fields:
      • max (optional): The maximum number of retries. Defaults to 0.
      • delay (optional): The delay between retries. It can be a number or a function. If it is a number, it represents the delay in milliseconds. Any non-finite or negative number will be replaced by 0. If it is a function, it will be invoked before each retry and given the current error as the first argument and the zero-based index of the current retry as the second argument, and it must return a number that represents the current delay needed in milliseconds. Any non-finite or negative number returned will be replaced by 0. Defaults to 0.
    • canRetry (optional): A function that determines whether a retry should be attempted or not. It takes the current error as the first argument and the zero-based index of the current retry as the second argument. It won't be called if the maximum attempt number defined by the max parameter is reached. If not provided, only the max parameter is checked to determine if the retry has to be performed.
    • onRetry (optional): A function that is called before every retry. It takes the current error as the first argument, the zero-based index of the current retry as the second argument, and the current retry delay in milliseconds as the third argument. The function is called before waiting for the current retry delay.

📤 Output

A proxy of the given retryable function. Only the call is changed, powered with a given retry strategy. The output can be used just like the original function.

📦 Installation

npm

npm install tentative

Yarn

yarn add tentative

pnpm

pnpm install tentative

Bun

bun install tentative

Deno

No installation required. Import the function directly from the URL https://deno.land/x/tentative/mod.ts (see examples below).

💡 Examples

For the sake of simplicity, here the tentative exported function is called t, but use whatever name that makes sense (such as tente, withRetries, retry, etc.).

Empower fetch with a retry strategy

Create a function that will work exactly like fetch but with 4 times maximum retries with a 2-second delay between retries.

// npm, Yarn, pnpm & Bun
import t from 'tentative'
// Deno
import t from 'https://deno.land/x/tentative/mod.ts'

const powerFetch = t(
  fetch,
  { attempts: { max: 4, delay: 2000 } }
)

await powerFetch(/* use it exactly as `fetch` */)
  .then(/* 🎉 */)
  .catch(/* in case it fails even after the retries 🤷 */)

Fixed delay with conditional and logging

Retry an async function 4 times maximum with a 5-second delay between retries. Retry only if the error is a DNS lookup error and log a message on every retry.

// npm, Yarn, pnpm & Bun
import t from 'tentative'
// Deno
import t from 'https://deno.land/x/tentative/mod.ts'

const asyncFct = (/* some arguments */) => new Promise(/* some great code */)

const max = 4

const p = t(
  asyncFct,
  {
    attempts: {
      max,
      delay: 5000
    },
    canRetry: (e) => e.message.includes('EAI_AGAIN'),
    onRetry: (e, i, delay) => console.log(`🌀 [${i + 1}/${max}] Retrying in ${delay}ms (${e.message})`)
  }
)

await p()

Random delays

Retry an async function 10 times maximum with a 3-second delay on DNS lookup errors and with a random delay between 5 to 10 seconds on other errors.

// npm, Yarn, pnpm & Bun
import t from 'tentative'
// Deno
import t from 'https://deno.land/x/tentative/mod.ts'

const asyncFct = (/* some arguments */) => new Promise(/* some great code */)

const p = t(
  asyncFct,
  {
    attempts: {
      max: 10,
      delay: (e) => e.message.includes('EAI_AGAIN') ? 3000 : 5000 + Math.random() * 5000
    }
  }
)

await p()

Incremental delays

Retry an async function 7 times maximum with a 1-second incremental delay starting at 2 seconds.

// npm, Yarn, pnpm & Bun
import t from 'tentative'
// Deno
import t from 'https://deno.land/x/tentative/mod.ts'

const asyncFct = (/* some arguments */) => new Promise(/* some great code */)

const p = t(
  asyncFct,
  {
    attempts: {
      max: 7,
      delay: (_, i) => 2000 + i * 1000
    }
  }
)

await p()

Fixed custom delays

Retry an async function 3 times maximum with different custom delays.

// npm, Yarn, pnpm & Bun
import t from 'tentative'
// Deno
import t from 'https://deno.land/x/tentative/mod.ts'

const asyncFct = (/* some arguments */) => new Promise(/* some great code */)

const delays = [2000, 4000, 9000]

const p = t(
  asyncFct,
  {
    attempts: {
      max: delays.length,
      delay: (_, i) => delays[i]
    }
  }
)

await p()