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

promises-fn-utils

v1.0.0

Published

Library with a set of utils and decorators to add to existing functions which returns promises a set of new features and behaviors without change nothing about the functions themselves

Downloads

4

Readme

Promises fn utils

This package is intended to provide a wide a variety of decorator functions to easily add capabilities to your functions which returns promises and this without modify the function's interface.

Installation

# using npm
npm install promises-fn-utils --save

# using yarn
yarn add promises-fn-utils

caching

createCache decorator allows you to add a cache layer to your function, so if after a call you call the function with the same parameters instead of making the operation again it will be returned from a cache

import { createCache } from 'promises-fn-utils'

function getPostByID(postID) {
  return fetch(`/api/post/${postID}`).then(response => response.json())
}

const applyCachePolicy = createCache({ ttl: 900000, maxEntries: 15 })

const cachedGetPostByID = applyCachePolicy(getPostByID)

// in your app
const post =  await cachedGetPostByID(1)
const secondPost =  await cachedGetPostByID(1) // this post will not be retrieved from the api but from the cache

Cache setup

| Name | Optional | Default | Description | | ------------- |:-------------:| -----:| -----:| | ttl | true | None | Time after which cache will be cleared, specified in milliseconds | | maxEntries | true | 15 | Maximum amount of different parameters that can be stored in the cache before being cleared |

retry

createRetryPolicy decorator allows to create a custom retry policy which can be applied to as many function as desired, the resulting retry function can be applied to any function and as this function gets executed and it fails it will be retried as many times as it was indicated at the retry options, besides in order to have a more robust retry system some delay can be applied before a retry attempt is performed and this delay time will be increased by a given factor in every attempt, the factor time is 2 applying the exponential backoff algorithm

import { createRetryPolicy } from 'promises-fn-utils'

const applyRetryPolicy = createRetryPolicy({ retries: 3, retryTime: 200 });

const getPostByIDWithRetries = applyRetryPolicy(getPostByID)

// And this policy can be applied to any function you desired
const fetchImportantStuff = applyRetryPolicy(fetcherFunction)

// Now you can use getPostByIDWithRetries and it will retry three times before throwing an error
await getPostByIDWithRetries(42)

In the example above the function getUserByIDWithRetries() will retry three times before throwing an error, these retries attempts will be delayed by 200ms and doubled by every attempt so in the first attempt will wait 200ms in the second one 400ms and in the final one 800ms, this is an exponential backoff and can be customized with the option retryFactor

import { createRetryPolicy } from 'promises-fn-utils'

const applyRetryPolicy = createRetryPolicy({ retries: 3, retryTime: 200, retryFactor: 4 });

const getPostByIDWithRetries = applyRetryPolicy(getPostByID)
await getPostByIDWithRetries(42)
// First attempt delay: 200ms
// Second attempt delay: 800ms
// Third attempt delay: 2400ms

Sometimes and based on our needs some retries make not sense, in order to customize if an attempt is necessary you can passed shouldRetry option

import { createRetryPolicy } from 'promises-fn-utils'

const applyRetryPolicy = createRetryPolicy({
  retries: 3,
  retryTime: 200,
  shouldRetry: err => err.status !== 404
});

const getPostByIDWithRetries = applyRetryPolicy(getPostByID)
await getPostByIDWithRetries(42)

shouldRetry is a predicate function that it will signal if a new retry make sense, in this case it will make a retry as long as the status error is different to 404(not found http status code), by default shouldRetry is not mandatory and returns true.

Retry setup

| Name | Optional | Default | Description | | ------------- |:-------------:| -----:| -----:| | retries | false | None | retry attempts before throwing an error | | retryTime | false | None | Initial delay time before a retry attempt is performed | | retryFactor | true | 2 | Increase factor for attempt's delay time | | shouldRetry | true | () => true | Predicate function which signal if an attempt must be performed |

batching

Batching is a strategy which allows to combine several identical incoming operations into a single one

import { createBatchedPromise } from 'promises-fn-utils'

const batchedPostFetcher = createBatchedPromise(getPostByID);

// Application spot 1
const post = await batchedPostFetcher(11)

// Application spot 2
const post = await batchedPostFetcher(11)

// Two operations executed but just one is being executed in the background at the time, the result will be send to both calling places

In the example above if two or more parts of the application execute at the same time the same function with the same parameters only one operation will be performed and the result will be distributed with all the callers.

This applies too if the same operation is executed before the last executed one has finished.

Queuing

Sometimes when concurrency plays a role in the system some shared state is unavoidable so in order to avoid race conditions we can queue all the incoming operations thus just one operation is apply over the shared state at the same time queuingTask() function makes this

import { queuingTask } from 'promises-fn-utils'

const queuedTask = queuingTask(delay)

await Promise.all([
  queuedTask(1000),
  queuedTask(1000),
  queuedTask(1000),
  queuedTask(1000),
])
// This will take 4000ms

Despite the fact that Promise.all runs the promises in parallel, queuingTask() makes sure that the executions are made in order and just one at the time, this of course has a cost in performance as a trade off with safety modifying a shared state, be cautious about using this.

Once

Some operation we might want to be executed just once in a certain flow so in order to handle this justOnce() function offers an interface to ensure that the decorated function is executed just once and in case we want to reset this we can make it with reset() function

import { justOnce } from 'promises-fn-utils'

const sendEmailOnlyOnce = justOnce(sendEmail)

// Application flow 1 ...
sendEmailOnlyOnce() // no matter how many times this is executed, this will send the email just once

// Another application flow ...
// Reset state, next time Application flow 1 is executed the email will be sent again
sendEmailOnlyOnce.reset()