@cjser/p-debounce 5.1.0-cjser.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,141 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // packages/@cjser/p-debounce/index.js
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ default: () => index_default
23
+ });
24
+ module.exports = __toCommonJS(index_exports);
25
+ var pDebounce = (functionToDebounce, wait, options = {}) => {
26
+ if (!Number.isFinite(wait)) {
27
+ throw new TypeError("Expected `wait` to be a finite number");
28
+ }
29
+ let leadingValue;
30
+ let timeout;
31
+ let promiseHandlers = [];
32
+ const onAbort = () => {
33
+ var _a;
34
+ clearTimeout(timeout);
35
+ timeout = void 0;
36
+ try {
37
+ (_a = options.signal) == null ? void 0 : _a.throwIfAborted();
38
+ } catch (error) {
39
+ for (const { reject } of promiseHandlers) {
40
+ reject(error);
41
+ }
42
+ promiseHandlers = [];
43
+ }
44
+ };
45
+ return function(...arguments_) {
46
+ return new Promise((resolve, reject) => {
47
+ var _a;
48
+ try {
49
+ (_a = options.signal) == null ? void 0 : _a.throwIfAborted();
50
+ } catch (error) {
51
+ reject(error);
52
+ return;
53
+ }
54
+ const shouldCallNow = options.before && !timeout;
55
+ clearTimeout(timeout);
56
+ timeout = setTimeout(async () => {
57
+ var _a2;
58
+ timeout = void 0;
59
+ const currentHandlers = promiseHandlers;
60
+ promiseHandlers = [];
61
+ try {
62
+ const result = options.before ? leadingValue : await functionToDebounce.apply(this, arguments_);
63
+ for (const { resolve: resolveFunction } of currentHandlers) {
64
+ resolveFunction(result);
65
+ }
66
+ } catch (error) {
67
+ for (const { reject: rejectFunction } of currentHandlers) {
68
+ rejectFunction(error);
69
+ }
70
+ }
71
+ leadingValue = void 0;
72
+ (_a2 = options.signal) == null ? void 0 : _a2.removeEventListener("abort", onAbort);
73
+ }, wait);
74
+ if (shouldCallNow) {
75
+ (async () => {
76
+ try {
77
+ leadingValue = await functionToDebounce.apply(this, arguments_);
78
+ resolve(leadingValue);
79
+ } catch (error) {
80
+ reject(error);
81
+ }
82
+ })();
83
+ } else {
84
+ promiseHandlers.push({ resolve, reject });
85
+ if (options.signal && promiseHandlers.length === 1) {
86
+ options.signal.addEventListener("abort", onAbort, { once: true });
87
+ }
88
+ }
89
+ });
90
+ };
91
+ };
92
+ pDebounce.promise = (function_, options = {}) => {
93
+ let currentPromise;
94
+ let queuedCall;
95
+ return async function(...arguments_) {
96
+ if (currentPromise) {
97
+ if (!options.after) {
98
+ return currentPromise;
99
+ }
100
+ queuedCall ??= { resolvers: [] };
101
+ queuedCall.arguments = arguments_;
102
+ queuedCall.context = this;
103
+ return new Promise((resolve, reject) => {
104
+ queuedCall.resolvers.push({ resolve, reject });
105
+ });
106
+ }
107
+ currentPromise = (async () => {
108
+ let result;
109
+ let initialError;
110
+ try {
111
+ result = await function_.apply(this, arguments_);
112
+ } catch (error) {
113
+ initialError = error;
114
+ }
115
+ while (queuedCall) {
116
+ const call = queuedCall;
117
+ queuedCall = void 0;
118
+ try {
119
+ const queuedResult = await function_.apply(call.context, call.arguments);
120
+ for (const { resolve } of call.resolvers) {
121
+ resolve(queuedResult);
122
+ }
123
+ } catch (error) {
124
+ for (const { reject } of call.resolvers) {
125
+ reject(error);
126
+ }
127
+ }
128
+ }
129
+ if (initialError) {
130
+ throw initialError;
131
+ }
132
+ return result;
133
+ })();
134
+ try {
135
+ return await currentPromise;
136
+ } finally {
137
+ currentPromise = void 0;
138
+ }
139
+ };
140
+ };
141
+ var index_default = pDebounce;
package/index.d.ts ADDED
@@ -0,0 +1,113 @@
1
+ export type Options = {
2
+ /**
3
+ Call the `fn` on the [leading edge of the timeout](https://css-tricks.com/debouncing-throttling-explained-examples/#article-header-id-1). Meaning immediately, instead of waiting for `wait` milliseconds.
4
+
5
+ @default false
6
+ */
7
+ readonly before?: boolean;
8
+
9
+ /**
10
+ An `AbortSignal` to cancel the debounced function.
11
+ */
12
+ readonly signal?: AbortSignal;
13
+ };
14
+
15
+ export type PromiseOptions = {
16
+ /**
17
+ If a call is made while a previous call is still running, queue the latest arguments and run the function again after the current execution completes.
18
+
19
+ @default false
20
+
21
+ Use cases:
22
+ - With `after: false` (default): API fetches, data loading, read operations - concurrent calls share the same result.
23
+ - With `after: true`: Saving data, file writes, state updates - ensures latest data is never lost.
24
+
25
+ @example
26
+ ```
27
+ import {setTimeout as delay} from 'timers/promises';
28
+ import pDebounce from '@cjser/p-debounce';
29
+
30
+ const save = async data => {
31
+ await delay(200);
32
+ console.log(`Saved: ${data}`);
33
+ return data;
34
+ };
35
+
36
+ const debouncedSave = pDebounce.promise(save, {after: true});
37
+
38
+ // If data changes while saving, it will save again with the latest data
39
+ debouncedSave('data1');
40
+ debouncedSave('data2'); // This will run after the first save completes
41
+ //=> Saved: data1
42
+ //=> Saved: data2
43
+ ```
44
+ */
45
+ readonly after?: boolean;
46
+ };
47
+
48
+ declare const pDebounce: {
49
+ /**
50
+ [Debounce](https://css-tricks.com/debouncing-throttling-explained-examples/) promise-returning & async functions.
51
+
52
+ @param fn - Promise-returning/async function to debounce.
53
+ @param wait - Milliseconds to wait before calling `fn`.
54
+ @returns A function that delays calling `fn` until after `wait` milliseconds have elapsed since the last time it was called.
55
+
56
+ @example
57
+ ```
58
+ import pDebounce from '@cjser/p-debounce';
59
+
60
+ const expensiveCall = async input => input;
61
+
62
+ const debouncedFunction = pDebounce(expensiveCall, 200);
63
+
64
+ for (const number of [1, 2, 3]) {
65
+ (async () => {
66
+ console.log(await debouncedFunction(number));
67
+ })();
68
+ }
69
+ //=> 3
70
+ //=> 3
71
+ //=> 3
72
+ ```
73
+ */
74
+ <This, ArgumentsType extends unknown[], ReturnType>(
75
+ fn: (this: This, ...arguments: ArgumentsType) => PromiseLike<ReturnType> | ReturnType,
76
+ wait: number,
77
+ options?: Options
78
+ ): (this: This, ...arguments: ArgumentsType) => Promise<ReturnType>;
79
+
80
+ /**
81
+ Execute `function_` unless a previous call is still pending, in which case, return the pending promise. Useful, for example, to avoid processing extra button clicks if the previous one is not complete.
82
+
83
+ @param function_ - Promise-returning/async function to debounce.
84
+
85
+ @example
86
+ ```
87
+ import {setTimeout as delay} from 'timers/promises';
88
+ import pDebounce from '@cjser/p-debounce';
89
+
90
+ const expensiveCall = async value => {
91
+ await delay(200);
92
+ return value;
93
+ };
94
+
95
+ const debouncedFunction = pDebounce.promise(expensiveCall);
96
+
97
+ for (const number of [1, 2, 3]) {
98
+ (async () => {
99
+ console.log(await debouncedFunction(number));
100
+ })();
101
+ }
102
+ //=> 1
103
+ //=> 1
104
+ //=> 1
105
+ ```
106
+ */
107
+ promise<This, ArgumentsType extends unknown[], ReturnType>(
108
+ function_: (this: This, ...arguments: ArgumentsType) => PromiseLike<ReturnType> | ReturnType,
109
+ options?: PromiseOptions
110
+ ): (this: This, ...arguments: ArgumentsType) => Promise<ReturnType>;
111
+ };
112
+
113
+ export default pDebounce;
package/index.js ADDED
@@ -0,0 +1,153 @@
1
+ const pDebounce = (functionToDebounce, wait, options = {}) => {
2
+ if (!Number.isFinite(wait)) {
3
+ throw new TypeError('Expected `wait` to be a finite number');
4
+ }
5
+
6
+ let leadingValue;
7
+ let timeout;
8
+ let promiseHandlers = []; // Single array of {resolve, reject}
9
+
10
+ const onAbort = () => {
11
+ clearTimeout(timeout);
12
+ timeout = undefined;
13
+
14
+ try {
15
+ options.signal?.throwIfAborted();
16
+ } catch (error) {
17
+ for (const {reject} of promiseHandlers) {
18
+ reject(error);
19
+ }
20
+
21
+ promiseHandlers = [];
22
+ }
23
+ };
24
+
25
+ return function (...arguments_) {
26
+ return new Promise((resolve, reject) => {
27
+ // Check if already aborted
28
+ try {
29
+ options.signal?.throwIfAborted();
30
+ } catch (error) {
31
+ reject(error);
32
+ return;
33
+ }
34
+
35
+ const shouldCallNow = options.before && !timeout;
36
+
37
+ clearTimeout(timeout);
38
+
39
+ timeout = setTimeout(async () => {
40
+ timeout = undefined;
41
+
42
+ // Capture the current handlers for this execution
43
+ const currentHandlers = promiseHandlers;
44
+
45
+ // Clear handlers for next cycle (new calls during execution will add to new list)
46
+ promiseHandlers = [];
47
+
48
+ try {
49
+ const result = options.before ? leadingValue : await functionToDebounce.apply(this, arguments_);
50
+
51
+ for (const {resolve: resolveFunction} of currentHandlers) {
52
+ resolveFunction(result);
53
+ }
54
+ } catch (error) {
55
+ for (const {reject: rejectFunction} of currentHandlers) {
56
+ rejectFunction(error);
57
+ }
58
+ }
59
+
60
+ // Clear leading value for next cycle
61
+ leadingValue = undefined;
62
+
63
+ // Remove abort listener
64
+ options.signal?.removeEventListener('abort', onAbort);
65
+ }, wait);
66
+
67
+ if (shouldCallNow) {
68
+ // Execute immediately for leading edge
69
+ (async () => {
70
+ try {
71
+ leadingValue = await functionToDebounce.apply(this, arguments_);
72
+ resolve(leadingValue);
73
+ } catch (error) {
74
+ reject(error);
75
+ }
76
+ })();
77
+ } else {
78
+ // Add to handlers for later resolution
79
+ promiseHandlers.push({resolve, reject});
80
+
81
+ // Set up abort listener (only once per batch)
82
+ if (options.signal && promiseHandlers.length === 1) {
83
+ options.signal.addEventListener('abort', onAbort, {once: true});
84
+ }
85
+ }
86
+ });
87
+ };
88
+ };
89
+
90
+ pDebounce.promise = (function_, options = {}) => {
91
+ let currentPromise;
92
+ let queuedCall;
93
+
94
+ return async function (...arguments_) {
95
+ if (currentPromise) {
96
+ if (!options.after) {
97
+ return currentPromise;
98
+ }
99
+
100
+ // Queue latest call (replacing any existing queue)
101
+ queuedCall ??= {resolvers: []};
102
+ queuedCall.arguments = arguments_;
103
+ queuedCall.context = this;
104
+
105
+ return new Promise((resolve, reject) => {
106
+ queuedCall.resolvers.push({resolve, reject});
107
+ });
108
+ }
109
+
110
+ currentPromise = (async () => {
111
+ let result;
112
+ let initialError;
113
+
114
+ try {
115
+ result = await function_.apply(this, arguments_);
116
+ } catch (error) {
117
+ initialError = error;
118
+ }
119
+
120
+ // Process queued calls regardless of initial result
121
+ while (queuedCall) {
122
+ const call = queuedCall;
123
+ queuedCall = undefined;
124
+
125
+ try {
126
+ // eslint-disable-next-line no-await-in-loop
127
+ const queuedResult = await function_.apply(call.context, call.arguments);
128
+ for (const {resolve} of call.resolvers) {
129
+ resolve(queuedResult);
130
+ }
131
+ } catch (error) {
132
+ for (const {reject} of call.resolvers) {
133
+ reject(error);
134
+ }
135
+ }
136
+ }
137
+
138
+ if (initialError) {
139
+ throw initialError;
140
+ }
141
+
142
+ return result;
143
+ })();
144
+
145
+ try {
146
+ return await currentPromise;
147
+ } finally {
148
+ currentPromise = undefined;
149
+ }
150
+ };
151
+ };
152
+
153
+ export default pDebounce;
package/license ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@cjser/p-debounce",
3
+ "version": "5.1.0-cjser.2",
4
+ "description": "Debounce promise-returning & async functions",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://code.moenext.com/3rdeye/cjser.git"
9
+ },
10
+ "funding": "https://github.com/sponsors/sindresorhus",
11
+ "author": {
12
+ "name": "Sindre Sorhus",
13
+ "email": "sindresorhus@gmail.com",
14
+ "url": "https://sindresorhus.com"
15
+ },
16
+ "type": "module",
17
+ "exports": {
18
+ "types": "./index.d.ts",
19
+ "require": "./dist-cjser/index.cjs",
20
+ "default": "./index.js"
21
+ },
22
+ "sideEffects": false,
23
+ "engines": {
24
+ "node": ">=20"
25
+ },
26
+ "scripts": {
27
+ "test": "xo && node --test && tsd"
28
+ },
29
+ "files": [
30
+ "index.js",
31
+ "index.d.ts",
32
+ "dist-cjser"
33
+ ],
34
+ "keywords": [
35
+ "promise",
36
+ "debounce",
37
+ "debounced",
38
+ "limit",
39
+ "limited",
40
+ "concurrency",
41
+ "throttle",
42
+ "throat",
43
+ "interval",
44
+ "rate",
45
+ "batch",
46
+ "ratelimit",
47
+ "task",
48
+ "queue",
49
+ "async",
50
+ "await",
51
+ "promises",
52
+ "bluebird"
53
+ ],
54
+ "devDependencies": {
55
+ "tsd": "^0.33.0",
56
+ "xo": "^1.2.2"
57
+ },
58
+ "types": "./index.d.ts",
59
+ "main": "./dist-cjser/index.cjs",
60
+ "cjser": {
61
+ "sourceVersion": "5.1.0",
62
+ "cjserVersion": 2,
63
+ "original": {
64
+ "name": "p-debounce",
65
+ "version": "5.1.0",
66
+ "exports": {
67
+ "types": "./index.d.ts",
68
+ "default": "./index.js"
69
+ },
70
+ "repository": "sindresorhus/p-debounce",
71
+ "files": [
72
+ "index.js",
73
+ "index.d.ts"
74
+ ],
75
+ "scripts": {
76
+ "test": "xo && node --test && tsd"
77
+ }
78
+ }
79
+ }
80
+ }
package/readme.md ADDED
@@ -0,0 +1,141 @@
1
+ # p-debounce
2
+
3
+ > [Debounce](https://css-tricks.com/debouncing-throttling-explained-examples/) promise-returning & async functions
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm install p-debounce
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```js
14
+ import pDebounce from 'p-debounce';
15
+
16
+ const expensiveCall = async input => input;
17
+
18
+ const debouncedFunction = pDebounce(expensiveCall, 200);
19
+
20
+ for (const number of [1, 2, 3]) {
21
+ (async () => {
22
+ console.log(await debouncedFunction(number));
23
+ })();
24
+ }
25
+ //=> 3
26
+ //=> 3
27
+ //=> 3
28
+ ```
29
+
30
+ ## API
31
+
32
+ ### pDebounce(fn, wait, options?)
33
+
34
+ Returns a function that delays calling `fn` until after `wait` milliseconds have elapsed since the last time it was called.
35
+
36
+ #### fn
37
+
38
+ Type: `Function`
39
+
40
+ Promise-returning/async function to debounce.
41
+
42
+ #### wait
43
+
44
+ Type: `number`
45
+
46
+ Milliseconds to wait before calling `fn`.
47
+
48
+ #### options
49
+
50
+ Type: `object`
51
+
52
+ ##### before
53
+
54
+ Type: `boolean`\
55
+ Default: `false`
56
+
57
+ Call the `fn` on the [leading edge of the timeout](https://css-tricks.com/debouncing-throttling-explained-examples/#article-header-id-1). Meaning immediately, instead of waiting for `wait` milliseconds.
58
+
59
+ ##### signal
60
+
61
+ Type: `AbortSignal`
62
+
63
+ An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) to cancel the debounced function.
64
+
65
+ ### pDebounce.promise(function_, options?)
66
+
67
+ Execute `function_` unless a previous call is still pending, in which case, return the pending promise. Useful, for example, to avoid processing extra button clicks if the previous one is not complete.
68
+
69
+ ```js
70
+ import {setTimeout as delay} from 'timers/promises';
71
+ import pDebounce from 'p-debounce';
72
+
73
+ const expensiveCall = async value => {
74
+ await delay(200);
75
+ return value;
76
+ };
77
+
78
+ const debouncedFunction = pDebounce.promise(expensiveCall);
79
+
80
+ for (const number of [1, 2, 3]) {
81
+ (async () => {
82
+ console.log(await debouncedFunction(number));
83
+ })();
84
+ }
85
+ //=> 1
86
+ //=> 1
87
+ //=> 1
88
+ ```
89
+
90
+ #### function_
91
+
92
+ Type: `Function`
93
+
94
+ Promise-returning/async function to debounce.
95
+
96
+ #### options
97
+
98
+ Type: `object`
99
+
100
+ ##### after
101
+
102
+ Type: `boolean`\
103
+ Default: `false`
104
+
105
+ If a call is made while a previous call is still running, queue the latest arguments and run the function again after the current execution completes.
106
+
107
+ Use cases:
108
+ - With `after: false` (default): API fetches, data loading, read operations - concurrent calls share the same result.
109
+ - With `after: true`: Saving data, file writes, state updates - ensures latest data is never lost.
110
+
111
+ ```js
112
+ import {setTimeout as delay} from 'timers/promises';
113
+ import pDebounce from 'p-debounce';
114
+
115
+ const save = async data => {
116
+ await delay(200);
117
+ console.log(`Saved: ${data}`);
118
+ return data;
119
+ };
120
+
121
+ const debouncedSave = pDebounce.promise(save, {after: true});
122
+
123
+ // If data changes while saving, it will save again with the latest data
124
+ debouncedSave('data1');
125
+ debouncedSave('data2'); // This will run after the first save completes
126
+ //=> Saved: data1
127
+ //=> Saved: data2
128
+ ```
129
+
130
+ ## Related
131
+
132
+ - [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
133
+ - [p-limit](https://github.com/sindresorhus/p-limit) - Run multiple promise-returning & async functions with limited concurrency
134
+ - [p-memoize](https://github.com/sindresorhus/p-memoize) - Memoize promise-returning & async functions
135
+ - [debounce-fn](https://github.com/sindresorhus/debounce-fn) - Debounce a function
136
+ - [More…](https://github.com/sindresorhus/promise-fun)
137
+
138
+ ## cjser
139
+
140
+ This package is a CommonJS-compatible build generated by cjser for projects that still need `require()` support. The source version matches the original npm package version, with a cjser prerelease suffix for this generated build.
141
+ Original repository: https://github.com/sindresorhus/p-debounce