You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

limit-once

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

limit-once - npm Package Compare versions

Comparing version

to
0.14.0

2

dist/index.d.ts
export { OncedFn, once } from './once.js';
export { OnceAsyncFn, onceAsync } from './once-async.js';
export { OncedAsyncFn, onceAsync } from './once-async.js';
type ResultValue<TFunc extends (this: any, ...args: any[]) => Promise<any>> = Awaited<ReturnType<TFunc>>;
type OnceAsyncFn<TFunc extends (this: any, ...args: any[]) => Promise<any>> = {
type OncedAsyncFn<TFunc extends (this: any, ...args: any[]) => Promise<any>> = {
/**

@@ -25,4 +25,4 @@ * Clear the cached `"fulfilled"` promise.

*/
declare function onceAsync<TFunc extends (...args: any[]) => Promise<any>>(fn: TFunc): OnceAsyncFn<TFunc>;
declare function onceAsync<TFunc extends (...args: any[]) => Promise<any>>(fn: TFunc): OncedAsyncFn<TFunc>;
export { type OnceAsyncFn, onceAsync };
export { type OncedAsyncFn, onceAsync };

@@ -14,3 +14,3 @@ function onceAsync(fn) {

function abort() {
rejectPendingPromise?.();
rejectPendingPromise == null ? void 0 : rejectPendingPromise();
}

@@ -17,0 +17,0 @@ const promise = new Promise((resolve, reject) => {

{
"name": "limit-once",
"version": "0.13.0",
"version": "0.14.0",
"author": "Alex Reardon <alexreardon@gmail.com>",

@@ -47,3 +47,3 @@ "repository": {

"prepublishOnly": "bun build:dist",
"build:dist": "bun tsup",
"build:dist": "bun build:clean && bun tsup",
"build:clean": "rimraf ./dist",

@@ -50,0 +50,0 @@ "check:all": "bun check:prettier && bun check:typescript && bun check:dist",

# limit-once
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/alexreardon/limit-once/check.yml?style=flat-square)
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/alexreardon/limit-once/check.yml)
Gives you the ability to ensure a `function` is only called `"once"`, and that that the result of that single `function` call is returned every time.
Cache the first successful result of a function call.

@@ -34,3 +34,3 @@ > [!NOTE]

Create a new `function` that wraps an existing function, where the wrapped function is only called once.
Create a new `function` that wraps an existing `function`, where the wrapped function is only called once.

@@ -59,2 +59,7 @@ ```ts

> [!NOTE]
> If you want the wrapped function to cache the result, but recompute the result when the arguments change: use [`memoize-one`](https://github.com/alexreardon/memoize-one)
### Only successful calls are cached
If the function being wrapped `throw`s an error, then that `throw` is not cached, and the wrapped function is allowed to be called again

@@ -87,3 +92,3 @@

### Cache clearing (`.clear()`)
### Cache clearing (`once(fn).clear()`)

@@ -124,19 +129,23 @@ You can clear the cache of a onced function by using the `.clear()` function property.

async function getLoggedInUser() {
await fetch('/user').json();
async function getPermissions(): Promise<Record<string, boolean>> {
// Note: could use "zod" to validate response shape
const response = await fetch('/permissions');
return await response.json();
}
// We don't want every call to `getLoggedInUser()` to call `fetch` again.
// We don't want every call to `getPermissions()` to call `fetch` again.
// Ideally we would store the result of the first successful call and return that!
const getLoggedInUserOnce = onceAsync(getLoggedInUser);
const getPermissionsOnce = onceAsync(getPermissions);
const user1 = await getLoggedInUserOnce();
const user1 = await getPermissionsOnce();
// subsequent calls won't call fetch, and will return the previously fulfilled promise value.
const user2 = await getLoggedInUserOnce();
const user2 = await getPermissionsOnce();
```
If the wrapped function that returns a promise has it's promise `"rejected"`, then the call will not be cached, and the underlying function can be called again.
### Only `"fulfilled"` `Promises` are cached
If the wrapped function has it's `Promise` `"rejected"`, then the `"rejected"` `Promise` will not be cached, and the underlying function can be called again.
```ts

@@ -167,18 +176,25 @@ import { onceAsync } from 'limit-once';

If multiple calls are made to the onced function while the original promise is still `"pending"`, then the original promise is re-used. This prevents multiple calls to the underlying function.
### Calls while a `Promise` is `"pending"`
If multiple calls are made to a `onceAsync(fn)` function while the original `Promise` is still `"pending"`, then the original `Promise` is re-used.
✨ This prevents multiple calls to the underlying function ✨
```ts
import { onceAsync } from 'limit-once';
async function getLoggedInUser() {
await fetch('/user').json();
async function getPermissions(): Promise<Record<string, boolean>> {
// Note: could use "zod" to validate response shape
const response = await fetch('/permissions');
return await response.json();
}
export const getLoggedInUserOnce = onceAsync(getLoggedInUser);
export const getPermissionsOnce = onceAsync(getPermissions);
const promise1 = getLoggedInUserOnce();
const promise1 = getPermissionsOnce();
// This second call to `getLoggedInUserOnce` while the `getLoggedInUser` promise
// This second call to `getPermissionsOnce()` while the `getPermissions()` promise
// is still "pending" will return the same promise that the first call created.
const promise2 = getLoggedInUserOnce();
// `fetch` is only called once (by the first call)
const promise2 = getPermissionsOnce();

@@ -188,5 +204,5 @@ console.log(promise1 === promise2); // "true"

### Cache clearing (`.clear()`)
### Cache clearing (`onceAsync(fn).clear()`)
You can clear the cache of a onced async function by using the `.clear()` function property.
You can clear the cache of a `onceAsync` function by using the `.clear()` function property.

@@ -193,0 +209,0 @@ ```ts

export { once, type OncedFn } from './once';
export { onceAsync, type OnceAsyncFn } from './once-async';
export { onceAsync, type OncedAsyncFn } from './once-async';

@@ -5,3 +5,3 @@ type ResultValue<TFunc extends (this: any, ...args: any[]) => Promise<any>> = Awaited<

export type OnceAsyncFn<TFunc extends (this: any, ...args: any[]) => Promise<any>> = {
export type OncedAsyncFn<TFunc extends (this: any, ...args: any[]) => Promise<any>> = {
/**

@@ -37,3 +37,3 @@ * Clear the cached `"fulfilled"` promise.

fn: TFunc,
): OnceAsyncFn<TFunc> {
): OncedAsyncFn<TFunc> {
type Result = ResultValue<TFunc>;

@@ -48,3 +48,3 @@

...args: Parameters<TFunc>
): ReturnType<OnceAsyncFn<TFunc>> {
): ReturnType<OncedAsyncFn<TFunc>> {
if (state.type === 'fulfilled') {

@@ -51,0 +51,0 @@ return state.promise;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet