@x-oasis/throttle 0.1.37 → 0.1.38

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.
@@ -1,22 +1,16 @@
1
1
 
2
- > @x-oasis/throttle@0.1.37 build /home/runner/work/x-oasis/x-oasis/packages/schedule/throttle
2
+ > @x-oasis/throttle@0.1.38 build /home/runner/work/x-oasis/x-oasis/packages/schedule/throttle
3
3
  > tsdx build --tsconfig tsconfig.build.json
4
4
 
5
5
  @rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
6
6
  @rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
7
7
  ⠙ Creating entry file
8
-  Building modules
9
- ✓ Creating entry file 5.5 secs
10
- ⠹ Building modules
8
+  Creating entry file 2.4 secs
9
+ Building modules
10
+ ⠹ Building modules
11
11
  ⠸ Building modules
12
12
  ⠼ Building modules
13
- ⠴ Building modules
14
- ⠦ Building modules
15
- ⠧ Building modules
16
- ⠇ Building modules
17
- ⠏ Building modules
18
- ⠋ Building modules
19
13
  [tsdx]: Your rootDir is currently set to "./". Please change your rootDir to "./src".
20
14
  TSDX has deprecated setting tsconfig.compilerOptions.rootDir to "./" as it caused buggy output for declarationMaps and more.
21
15
  You may also need to change your include to remove "test", which also caused declarations to be unnecessarily created for test files.
22
- ✓ Building modules 8 secs
16
+ ✓ Building modules 3.2 secs
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @x-oasis/throttle
2
2
 
3
+ ## 0.1.38
4
+
5
+ ### Patch Changes
6
+
7
+ - f1aae14: bump version
8
+ - Updated dependencies [f1aae14]
9
+ - @x-oasis/default-boolean-value@0.1.38
10
+ - @x-oasis/debounce@0.1.38
11
+
3
12
  ## 0.1.37
4
13
 
5
14
  ### Patch Changes
package/README.md CHANGED
@@ -1,19 +1,176 @@
1
1
  # @x-oasis/throttle
2
2
 
3
+ Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds.
4
+
3
5
  ## Installation
4
6
 
5
7
  ```bash
6
- $ npm i @x-oasis/throttle
8
+ npm install @x-oasis/throttle
9
+ # or
10
+ pnpm add @x-oasis/throttle
11
+ # or
12
+ yarn add @x-oasis/throttle
7
13
  ```
8
14
 
9
- ## How to use
15
+ ## Usage
16
+
17
+ ### Basic Usage
10
18
 
11
19
  ```typescript
12
- import throttle from '@x-oasis/throttle'
20
+ import throttle from '@x-oasis/throttle';
21
+
22
+ // Avoid excessively updating the position while scrolling.
23
+ const updatePosition = () => {
24
+ // Update scroll position
25
+ };
26
+
27
+ const throttled = throttle(updatePosition, 100);
28
+ window.addEventListener('scroll', throttled);
13
29
  ```
14
30
 
15
- ## How to run test
31
+ ### With Options
16
32
 
17
- ```bash
18
- $ pnpm test
19
- ```
33
+ ```typescript
34
+ import throttle from '@x-oasis/throttle';
35
+
36
+ const renewToken = () => {
37
+ // Renew authentication token
38
+ };
39
+
40
+ // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
41
+ const throttled = throttle(renewToken, 300000, {
42
+ trailing: false
43
+ });
44
+ ```
45
+
46
+ ### Cancel and Flush
47
+
48
+ The throttled function comes with a `cancel` method to cancel delayed `func` invocations and a `flush` method to immediately invoke them.
49
+
50
+ ```typescript
51
+ import throttle from '@x-oasis/throttle';
52
+
53
+ const throttled = throttle(updatePosition, 100);
54
+
55
+ // Cancel the trailing throttled invocation.
56
+ throttled.cancel();
57
+
58
+ // Flush the trailing throttled invocation.
59
+ throttled.flush();
60
+ ```
61
+
62
+ ## API
63
+
64
+ ### `throttle(func, wait, options?)`
65
+
66
+ Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds.
67
+
68
+ #### Parameters
69
+
70
+ - `func` (`Function`): The function to throttle.
71
+ - `wait` (`number`, default: `0`): The number of milliseconds to throttle invocations to.
72
+ - `options` (`Object`, optional): The options object.
73
+ - `leading` (`boolean`, default: `true`): Specify invoking on the leading edge of the timeout.
74
+ - `trailing` (`boolean`, default: `true`): Specify invoking on the trailing edge of the timeout.
75
+
76
+ #### Returns
77
+
78
+ Returns the new throttled function with the following methods:
79
+
80
+ - `cancel()`: Cancels delayed `func` invocations.
81
+ - `flush()`: Immediately invokes the delayed `func` invocation.
82
+
83
+ ## Examples
84
+
85
+ ### Scroll Handler
86
+
87
+ ```typescript
88
+ import throttle from '@x-oasis/throttle';
89
+
90
+ const handleScroll = () => {
91
+ // Update UI based on scroll position
92
+ console.log('Scroll position:', window.scrollY);
93
+ };
94
+
95
+ const throttledScroll = throttle(handleScroll, 100);
96
+
97
+ window.addEventListener('scroll', throttledScroll);
98
+
99
+ // Cleanup
100
+ window.removeEventListener('scroll', throttledScroll);
101
+ throttledScroll.cancel();
102
+ ```
103
+
104
+ ### Mouse Move Handler
105
+
106
+ ```typescript
107
+ import throttle from '@x-oasis/throttle';
108
+
109
+ const handleMouseMove = (event: MouseEvent) => {
110
+ // Track mouse position
111
+ console.log('Mouse position:', event.clientX, event.clientY);
112
+ };
113
+
114
+ const throttledMouseMove = throttle(handleMouseMove, 50);
115
+
116
+ document.addEventListener('mousemove', throttledMouseMove);
117
+ ```
118
+
119
+ ### Leading and Trailing
120
+
121
+ ```typescript
122
+ import throttle from '@x-oasis/throttle';
123
+
124
+ const logMessage = (message: string) => {
125
+ console.log(message);
126
+ };
127
+
128
+ // Execute immediately on first call, then wait for trailing edge
129
+ const throttled = throttle(logMessage, 1000, {
130
+ leading: true,
131
+ trailing: true
132
+ });
133
+
134
+ throttled('First'); // Executes immediately
135
+ throttled('Second'); // Ignored
136
+ throttled('Third'); // Ignored
137
+ // After 1000ms, 'Third' executes (trailing edge)
138
+
139
+ // Only execute on trailing edge
140
+ const trailingOnly = throttle(logMessage, 1000, {
141
+ leading: false,
142
+ trailing: true
143
+ });
144
+
145
+ trailingOnly('First'); // Not executed immediately
146
+ trailingOnly('Second'); // Not executed
147
+ trailingOnly('Third'); // Not executed
148
+ // After 1000ms, 'Third' executes
149
+ ```
150
+
151
+ ## Differences from Debounce
152
+
153
+ - **Throttle**: Executes the function at most once per `wait` milliseconds, regardless of how many times it's called.
154
+ - **Debounce**: Delays execution until after `wait` milliseconds have elapsed since the last invocation.
155
+
156
+ ### When to Use Throttle
157
+
158
+ - Scroll events
159
+ - Mouse move events
160
+ - Window resize events (when you want periodic updates)
161
+ - API calls that should happen at regular intervals
162
+
163
+ ### When to Use Debounce
164
+
165
+ - Search input (wait for user to stop typing)
166
+ - Button clicks (prevent double-clicks)
167
+ - Window resize events (when you only care about the final size)
168
+
169
+ ## See Also
170
+
171
+ - [Lodash throttle](https://lodash.com/docs/#throttle)
172
+ - [@x-oasis/debounce](../debounce/README.md) - Creates a debounced function
173
+
174
+ ## License
175
+
176
+ ISC
package/dist/index.d.ts CHANGED
@@ -1,3 +1,8 @@
1
- export default function throttle(fn: Function, threshold?: number, fallbackOptions?: {
2
- persistArgs?: (...args: any[]) => any;
3
- } | boolean): (...args: any[]) => any;
1
+ export declare type ThrottleOptions = {
2
+ leading?: boolean;
3
+ trailing?: boolean;
4
+ };
5
+ export default function throttle(func: (...args: any[]) => any, wait?: number, options?: ThrottleOptions): ((...args: any[]) => any) & {
6
+ cancel: () => void;
7
+ flush: () => void;
8
+ };
@@ -2,27 +2,21 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- function throttle(fn, threshold, fallbackOptions) {
6
- if (threshold === void 0) {
7
- threshold = 250;
5
+ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
+
7
+ var debounce = _interopDefault(require('@x-oasis/debounce'));
8
+
9
+ function throttle(func, wait, options) {
10
+ if (wait === void 0) {
11
+ wait = 0;
8
12
  }
9
- var last = 0;
10
- var _args = [];
11
- return function throttled() {
12
- var now = Date.now();
13
- var persistArgs = typeof fallbackOptions === 'object' ? fallbackOptions.persistArgs : null;
14
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
15
- args[_key] = arguments[_key];
16
- }
17
- _args = args;
18
- if (typeof persistArgs === 'function') {
19
- _args = persistArgs(args);
20
- }
21
- if (now - last > threshold) {
22
- last = now;
23
- return fn.apply(this, args);
24
- }
25
- };
13
+ var leading = (options == null ? void 0 : options.leading) !== undefined ? options.leading : true;
14
+ var trailing = (options == null ? void 0 : options.trailing) !== undefined ? options.trailing : true;
15
+ return debounce(func, wait, {
16
+ leading: leading,
17
+ trailing: trailing,
18
+ maxWait: wait
19
+ });
26
20
  }
27
21
 
28
22
  exports.default = throttle;
@@ -1 +1 @@
1
- {"version":3,"file":"throttle.cjs.development.js","sources":["../src/index.ts"],"sourcesContent":["/**\n *\n * @param fn\n * @param threshold\n * @returns\n *\n * trigger first, then trigger on the last\n */\n\nexport default function throttle(\n fn: Function,\n threshold = 250,\n fallbackOptions?:\n | {\n persistArgs?: (...args: any[]) => any;\n }\n | boolean\n) {\n let last = 0;\n let _args = [];\n\n return function throttled(...args: any[]) {\n const now = Date.now();\n\n const persistArgs =\n typeof fallbackOptions === 'object' ? fallbackOptions.persistArgs : null;\n\n _args = args;\n\n if (typeof persistArgs === 'function') {\n _args = persistArgs(args);\n }\n\n if (now - last > threshold) {\n last = now;\n\n return fn.apply(this, args);\n }\n };\n}\n"],"names":["throttle","fn","threshold","fallbackOptions","last","_args","throttled","now","Date","persistArgs","_len","arguments","length","args","Array","_key","apply"],"mappings":";;;;SASwBA,QAAQA,CAC9BC,EAAY,EACZC,SAAS,EACTC,eAIW;MALXD,SAAS;IAATA,SAAS,GAAG,GAAG;;EAOf,IAAIE,IAAI,GAAG,CAAC;EACZ,IAAIC,KAAK,GAAG,EAAE;EAEd,OAAO,SAASC,SAASA;IACvB,IAAMC,GAAG,GAAGC,IAAI,CAACD,GAAG,EAAE;IAEtB,IAAME,WAAW,GACf,OAAON,eAAe,KAAK,QAAQ,GAAGA,eAAe,CAACM,WAAW,GAAG,IAAI;IAAC,SAAAC,IAAA,GAAAC,SAAA,CAAAC,MAAA,EAJhDC,IAAW,OAAAC,KAAA,CAAAJ,IAAA,GAAAK,IAAA,MAAAA,IAAA,GAAAL,IAAA,EAAAK,IAAA;MAAXF,IAAW,CAAAE,IAAA,IAAAJ,SAAA,CAAAI,IAAA;;IAMtCV,KAAK,GAAGQ,IAAI;IAEZ,IAAI,OAAOJ,WAAW,KAAK,UAAU,EAAE;MACrCJ,KAAK,GAAGI,WAAW,CAACI,IAAI,CAAC;;IAG3B,IAAIN,GAAG,GAAGH,IAAI,GAAGF,SAAS,EAAE;MAC1BE,IAAI,GAAGG,GAAG;MAEV,OAAON,EAAE,CAACe,KAAK,CAAC,IAAI,EAAEH,IAAI,CAAC;;GAE9B;AACH;;;;"}
1
+ {"version":3,"file":"throttle.cjs.development.js","sources":["../src/index.ts"],"sourcesContent":["import debounce from '@x-oasis/debounce';\n\n/**\n * Options for throttle function\n * @see https://lodash.com/docs/#throttle\n */\nexport type ThrottleOptions = {\n /**\n * Specify invoking on the leading edge of the timeout.\n * @default true\n */\n leading?: boolean;\n /**\n * Specify invoking on the trailing edge of the timeout.\n * @default true\n */\n trailing?: boolean;\n};\n\n/**\n * Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds.\n *\n * The throttled function comes with a `cancel` method to cancel delayed `func` invocations\n * and a `flush` method to immediately invoke them.\n *\n * @param func - The function to throttle\n * @param wait - The number of milliseconds to throttle invocations to\n * @param options - The options object\n * @returns Returns the new throttled function\n *\n * @example\n * ```typescript\n * // Avoid excessively updating the position while scrolling.\n * const throttled = throttle(updatePosition, 100);\n * window.addEventListener('scroll', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * throttled.cancel();\n *\n * // Flush the trailing throttled invocation.\n * throttled.flush();\n * ```\n *\n * @example\n * ```typescript\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * const throttled = throttle(renewToken, 300000, {\n * 'trailing': false\n * });\n * ```\n *\n * @see https://lodash.com/docs/#throttle\n */\nexport default function throttle(\n func: (...args: any[]) => any,\n wait = 0,\n options?: ThrottleOptions\n): ((...args: any[]) => any) & {\n cancel: () => void;\n flush: () => void;\n} {\n const leading = options?.leading !== undefined ? options.leading : true;\n const trailing = options?.trailing !== undefined ? options.trailing : true;\n\n // Throttle is essentially debounce with maxWait set to wait\n // This ensures the function is invoked at most once per wait period\n return debounce(func, wait, {\n leading,\n trailing,\n maxWait: wait,\n });\n}\n"],"names":["throttle","func","wait","options","leading","undefined","trailing","debounce","maxWait"],"mappings":";;;;;;;;SAqDwBA,QAAQA,CAC9BC,IAA6B,EAC7BC,IAAI,EACJC,OAAyB;MADzBD,IAAI;IAAJA,IAAI,GAAG,CAAC;;EAMR,IAAME,OAAO,GAAG,CAAAD,OAAO,oBAAPA,OAAO,CAAEC,OAAO,MAAKC,SAAS,GAAGF,OAAO,CAACC,OAAO,GAAG,IAAI;EACvE,IAAME,QAAQ,GAAG,CAAAH,OAAO,oBAAPA,OAAO,CAAEG,QAAQ,MAAKD,SAAS,GAAGF,OAAO,CAACG,QAAQ,GAAG,IAAI;EAI1E,OAAOC,QAAQ,CAACN,IAAI,EAAEC,IAAI,EAAE;IAC1BE,OAAO,EAAPA,OAAO;IACPE,QAAQ,EAARA,QAAQ;IACRE,OAAO,EAAEN;GACV,CAAC;AACJ;;;;"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=function(e,t,r){void 0===t&&(t=250);var n=0;return function(){for(var o=Date.now(),u="object"==typeof r?r.persistArgs:null,f=arguments.length,i=new Array(f),s=0;s<f;s++)i[s]=arguments[s];if("function"==typeof u&&u(i),o-n>t)return n=o,e.apply(this,i)}};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,i=(e=require("@x-oasis/debounce"))&&"object"==typeof e&&"default"in e?e.default:e;exports.default=function(e,t,l){return void 0===t&&(t=0),i(e,t,{leading:void 0===(null==l?void 0:l.leading)||l.leading,trailing:void 0===(null==l?void 0:l.trailing)||l.trailing,maxWait:t})};
2
2
  //# sourceMappingURL=throttle.cjs.production.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"throttle.cjs.production.min.js","sources":["../src/index.ts"],"sourcesContent":["/**\n *\n * @param fn\n * @param threshold\n * @returns\n *\n * trigger first, then trigger on the last\n */\n\nexport default function throttle(\n fn: Function,\n threshold = 250,\n fallbackOptions?:\n | {\n persistArgs?: (...args: any[]) => any;\n }\n | boolean\n) {\n let last = 0;\n let _args = [];\n\n return function throttled(...args: any[]) {\n const now = Date.now();\n\n const persistArgs =\n typeof fallbackOptions === 'object' ? fallbackOptions.persistArgs : null;\n\n _args = args;\n\n if (typeof persistArgs === 'function') {\n _args = persistArgs(args);\n }\n\n if (now - last > threshold) {\n last = now;\n\n return fn.apply(this, args);\n }\n };\n}\n"],"names":["fn","threshold","fallbackOptions","last","now","Date","persistArgs","_len","arguments","length","args","Array","_key","apply","this"],"mappings":"6FAUEA,EACAC,EACAC,YADAD,IAAAA,EAAY,KAOZ,IAAIE,EAAO,EAGX,OAAO,WAIsE,IAH3E,IAAMC,EAAMC,KAAKD,MAEXE,EACuB,iBAApBJ,EAA+BA,EAAgBI,YAAc,KAAKC,EAAAC,UAAAC,OAJhDC,MAAWC,MAAAJ,GAAAK,IAAAA,EAAAL,EAAAK,IAAXF,EAAWE,GAAAJ,UAAAI,GAYtC,GAJ2B,mBAAhBN,GACDA,EAAYI,GAGlBN,EAAMD,EAAOF,EAGf,OAFAE,EAAOC,EAEAJ,EAAGa,MAAMC,KAAMJ"}
1
+ {"version":3,"file":"throttle.cjs.production.min.js","sources":["../src/index.ts"],"sourcesContent":["import debounce from '@x-oasis/debounce';\n\n/**\n * Options for throttle function\n * @see https://lodash.com/docs/#throttle\n */\nexport type ThrottleOptions = {\n /**\n * Specify invoking on the leading edge of the timeout.\n * @default true\n */\n leading?: boolean;\n /**\n * Specify invoking on the trailing edge of the timeout.\n * @default true\n */\n trailing?: boolean;\n};\n\n/**\n * Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds.\n *\n * The throttled function comes with a `cancel` method to cancel delayed `func` invocations\n * and a `flush` method to immediately invoke them.\n *\n * @param func - The function to throttle\n * @param wait - The number of milliseconds to throttle invocations to\n * @param options - The options object\n * @returns Returns the new throttled function\n *\n * @example\n * ```typescript\n * // Avoid excessively updating the position while scrolling.\n * const throttled = throttle(updatePosition, 100);\n * window.addEventListener('scroll', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * throttled.cancel();\n *\n * // Flush the trailing throttled invocation.\n * throttled.flush();\n * ```\n *\n * @example\n * ```typescript\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * const throttled = throttle(renewToken, 300000, {\n * 'trailing': false\n * });\n * ```\n *\n * @see https://lodash.com/docs/#throttle\n */\nexport default function throttle(\n func: (...args: any[]) => any,\n wait = 0,\n options?: ThrottleOptions\n): ((...args: any[]) => any) & {\n cancel: () => void;\n flush: () => void;\n} {\n const leading = options?.leading !== undefined ? options.leading : true;\n const trailing = options?.trailing !== undefined ? options.trailing : true;\n\n // Throttle is essentially debounce with maxWait set to wait\n // This ensures the function is invoked at most once per wait period\n return debounce(func, wait, {\n leading,\n trailing,\n maxWait: wait,\n });\n}\n"],"names":["func","wait","options","debounce","leading","undefined","trailing","maxWait"],"mappings":"qLAsDEA,EACAC,EACAC,GAUA,gBAXAD,IAAAA,EAAO,GAWAE,EAASH,EAAMC,EAAM,CAC1BG,aANmCC,WAArBH,SAAAA,EAASE,UAAwBF,EAAQE,QAOvDE,cANqCD,WAAtBH,SAAAA,EAASI,WAAyBJ,EAAQI,SAOzDC,QAASN"}
@@ -1,24 +1,16 @@
1
- function throttle(fn, threshold, fallbackOptions) {
2
- if (threshold === void 0) {
3
- threshold = 250;
1
+ import debounce from '@x-oasis/debounce';
2
+
3
+ function throttle(func, wait, options) {
4
+ if (wait === void 0) {
5
+ wait = 0;
4
6
  }
5
- var last = 0;
6
- var _args = [];
7
- return function throttled() {
8
- var now = Date.now();
9
- var persistArgs = typeof fallbackOptions === 'object' ? fallbackOptions.persistArgs : null;
10
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
11
- args[_key] = arguments[_key];
12
- }
13
- _args = args;
14
- if (typeof persistArgs === 'function') {
15
- _args = persistArgs(args);
16
- }
17
- if (now - last > threshold) {
18
- last = now;
19
- return fn.apply(this, args);
20
- }
21
- };
7
+ var leading = (options == null ? void 0 : options.leading) !== undefined ? options.leading : true;
8
+ var trailing = (options == null ? void 0 : options.trailing) !== undefined ? options.trailing : true;
9
+ return debounce(func, wait, {
10
+ leading: leading,
11
+ trailing: trailing,
12
+ maxWait: wait
13
+ });
22
14
  }
23
15
 
24
16
  export default throttle;
@@ -1 +1 @@
1
- {"version":3,"file":"throttle.esm.js","sources":["../src/index.ts"],"sourcesContent":["/**\n *\n * @param fn\n * @param threshold\n * @returns\n *\n * trigger first, then trigger on the last\n */\n\nexport default function throttle(\n fn: Function,\n threshold = 250,\n fallbackOptions?:\n | {\n persistArgs?: (...args: any[]) => any;\n }\n | boolean\n) {\n let last = 0;\n let _args = [];\n\n return function throttled(...args: any[]) {\n const now = Date.now();\n\n const persistArgs =\n typeof fallbackOptions === 'object' ? fallbackOptions.persistArgs : null;\n\n _args = args;\n\n if (typeof persistArgs === 'function') {\n _args = persistArgs(args);\n }\n\n if (now - last > threshold) {\n last = now;\n\n return fn.apply(this, args);\n }\n };\n}\n"],"names":["throttle","fn","threshold","fallbackOptions","last","_args","throttled","now","Date","persistArgs","_len","arguments","length","args","Array","_key","apply"],"mappings":"SASwBA,QAAQA,CAC9BC,EAAY,EACZC,SAAS,EACTC,eAIW;MALXD,SAAS;IAATA,SAAS,GAAG,GAAG;;EAOf,IAAIE,IAAI,GAAG,CAAC;EACZ,IAAIC,KAAK,GAAG,EAAE;EAEd,OAAO,SAASC,SAASA;IACvB,IAAMC,GAAG,GAAGC,IAAI,CAACD,GAAG,EAAE;IAEtB,IAAME,WAAW,GACf,OAAON,eAAe,KAAK,QAAQ,GAAGA,eAAe,CAACM,WAAW,GAAG,IAAI;IAAC,SAAAC,IAAA,GAAAC,SAAA,CAAAC,MAAA,EAJhDC,IAAW,OAAAC,KAAA,CAAAJ,IAAA,GAAAK,IAAA,MAAAA,IAAA,GAAAL,IAAA,EAAAK,IAAA;MAAXF,IAAW,CAAAE,IAAA,IAAAJ,SAAA,CAAAI,IAAA;;IAMtCV,KAAK,GAAGQ,IAAI;IAEZ,IAAI,OAAOJ,WAAW,KAAK,UAAU,EAAE;MACrCJ,KAAK,GAAGI,WAAW,CAACI,IAAI,CAAC;;IAG3B,IAAIN,GAAG,GAAGH,IAAI,GAAGF,SAAS,EAAE;MAC1BE,IAAI,GAAGG,GAAG;MAEV,OAAON,EAAE,CAACe,KAAK,CAAC,IAAI,EAAEH,IAAI,CAAC;;GAE9B;AACH;;;;"}
1
+ {"version":3,"file":"throttle.esm.js","sources":["../src/index.ts"],"sourcesContent":["import debounce from '@x-oasis/debounce';\n\n/**\n * Options for throttle function\n * @see https://lodash.com/docs/#throttle\n */\nexport type ThrottleOptions = {\n /**\n * Specify invoking on the leading edge of the timeout.\n * @default true\n */\n leading?: boolean;\n /**\n * Specify invoking on the trailing edge of the timeout.\n * @default true\n */\n trailing?: boolean;\n};\n\n/**\n * Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds.\n *\n * The throttled function comes with a `cancel` method to cancel delayed `func` invocations\n * and a `flush` method to immediately invoke them.\n *\n * @param func - The function to throttle\n * @param wait - The number of milliseconds to throttle invocations to\n * @param options - The options object\n * @returns Returns the new throttled function\n *\n * @example\n * ```typescript\n * // Avoid excessively updating the position while scrolling.\n * const throttled = throttle(updatePosition, 100);\n * window.addEventListener('scroll', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * throttled.cancel();\n *\n * // Flush the trailing throttled invocation.\n * throttled.flush();\n * ```\n *\n * @example\n * ```typescript\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * const throttled = throttle(renewToken, 300000, {\n * 'trailing': false\n * });\n * ```\n *\n * @see https://lodash.com/docs/#throttle\n */\nexport default function throttle(\n func: (...args: any[]) => any,\n wait = 0,\n options?: ThrottleOptions\n): ((...args: any[]) => any) & {\n cancel: () => void;\n flush: () => void;\n} {\n const leading = options?.leading !== undefined ? options.leading : true;\n const trailing = options?.trailing !== undefined ? options.trailing : true;\n\n // Throttle is essentially debounce with maxWait set to wait\n // This ensures the function is invoked at most once per wait period\n return debounce(func, wait, {\n leading,\n trailing,\n maxWait: wait,\n });\n}\n"],"names":["throttle","func","wait","options","leading","undefined","trailing","debounce","maxWait"],"mappings":";;SAqDwBA,QAAQA,CAC9BC,IAA6B,EAC7BC,IAAI,EACJC,OAAyB;MADzBD,IAAI;IAAJA,IAAI,GAAG,CAAC;;EAMR,IAAME,OAAO,GAAG,CAAAD,OAAO,oBAAPA,OAAO,CAAEC,OAAO,MAAKC,SAAS,GAAGF,OAAO,CAACC,OAAO,GAAG,IAAI;EACvE,IAAME,QAAQ,GAAG,CAAAH,OAAO,oBAAPA,OAAO,CAAEG,QAAQ,MAAKD,SAAS,GAAGF,OAAO,CAACG,QAAQ,GAAG,IAAI;EAI1E,OAAOC,QAAQ,CAACN,IAAI,EAAEC,IAAI,EAAE;IAC1BE,OAAO,EAAPA,OAAO;IACPE,QAAQ,EAARA,QAAQ;IACRE,OAAO,EAAEN;GACV,CAAC;AACJ;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-oasis/throttle",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "description": "throttle function",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -13,6 +13,10 @@
13
13
  "devDependencies": {
14
14
  "tsdx": "^0.14.1"
15
15
  },
16
+ "dependencies": {
17
+ "@x-oasis/default-boolean-value": "0.1.38",
18
+ "@x-oasis/debounce": "0.1.38"
19
+ },
16
20
  "scripts": {
17
21
  "build": "tsdx build --tsconfig tsconfig.build.json",
18
22
  "clean": "rimraf ./dist",
package/src/index.ts CHANGED
@@ -1,40 +1,72 @@
1
+ import debounce from '@x-oasis/debounce';
2
+
3
+ /**
4
+ * Options for throttle function
5
+ * @see https://lodash.com/docs/#throttle
6
+ */
7
+ export type ThrottleOptions = {
8
+ /**
9
+ * Specify invoking on the leading edge of the timeout.
10
+ * @default true
11
+ */
12
+ leading?: boolean;
13
+ /**
14
+ * Specify invoking on the trailing edge of the timeout.
15
+ * @default true
16
+ */
17
+ trailing?: boolean;
18
+ };
19
+
1
20
  /**
21
+ * Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds.
22
+ *
23
+ * The throttled function comes with a `cancel` method to cancel delayed `func` invocations
24
+ * and a `flush` method to immediately invoke them.
25
+ *
26
+ * @param func - The function to throttle
27
+ * @param wait - The number of milliseconds to throttle invocations to
28
+ * @param options - The options object
29
+ * @returns Returns the new throttled function
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * // Avoid excessively updating the position while scrolling.
34
+ * const throttled = throttle(updatePosition, 100);
35
+ * window.addEventListener('scroll', throttled);
36
+ *
37
+ * // Cancel the trailing throttled invocation.
38
+ * throttled.cancel();
2
39
  *
3
- * @param fn
4
- * @param threshold
5
- * @returns
40
+ * // Flush the trailing throttled invocation.
41
+ * throttled.flush();
42
+ * ```
6
43
  *
7
- * trigger first, then trigger on the last
44
+ * @example
45
+ * ```typescript
46
+ * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
47
+ * const throttled = throttle(renewToken, 300000, {
48
+ * 'trailing': false
49
+ * });
50
+ * ```
51
+ *
52
+ * @see https://lodash.com/docs/#throttle
8
53
  */
9
-
10
54
  export default function throttle(
11
- fn: Function,
12
- threshold = 250,
13
- fallbackOptions?:
14
- | {
15
- persistArgs?: (...args: any[]) => any;
16
- }
17
- | boolean
18
- ) {
19
- let last = 0;
20
- let _args = [];
21
-
22
- return function throttled(...args: any[]) {
23
- const now = Date.now();
24
-
25
- const persistArgs =
26
- typeof fallbackOptions === 'object' ? fallbackOptions.persistArgs : null;
27
-
28
- _args = args;
29
-
30
- if (typeof persistArgs === 'function') {
31
- _args = persistArgs(args);
32
- }
33
-
34
- if (now - last > threshold) {
35
- last = now;
55
+ func: (...args: any[]) => any,
56
+ wait = 0,
57
+ options?: ThrottleOptions
58
+ ): ((...args: any[]) => any) & {
59
+ cancel: () => void;
60
+ flush: () => void;
61
+ } {
62
+ const leading = options?.leading !== undefined ? options.leading : true;
63
+ const trailing = options?.trailing !== undefined ? options.trailing : true;
36
64
 
37
- return fn.apply(this, args);
38
- }
39
- };
65
+ // Throttle is essentially debounce with maxWait set to wait
66
+ // This ensures the function is invoked at most once per wait period
67
+ return debounce(func, wait, {
68
+ leading,
69
+ trailing,
70
+ maxWait: wait,
71
+ });
40
72
  }
package/test/test.spec.ts CHANGED
@@ -1,5 +1,235 @@
1
- import { expect, test } from 'vitest';
1
+ import { expect, test, vi, beforeEach, afterEach } from 'vitest';
2
+ import throttle from '../src/index';
2
3
 
3
- test('vitest', async () => {
4
- expect('vitest').toBe('vitest');
4
+ beforeEach(() => {
5
+ vi.useFakeTimers();
6
+ });
7
+
8
+ afterEach(() => {
9
+ vi.restoreAllMocks();
10
+ });
11
+
12
+ test('throttle basic functionality', () => {
13
+ const fn = vi.fn();
14
+ const throttled = throttle(fn, 100);
15
+
16
+ throttled(1);
17
+ expect(fn).toHaveBeenCalledTimes(1);
18
+ expect(fn).toHaveBeenCalledWith(1);
19
+
20
+ throttled(2);
21
+ throttled(3);
22
+ expect(fn).toHaveBeenCalledTimes(1); // Still only called once
23
+
24
+ vi.advanceTimersByTime(100);
25
+ expect(fn).toHaveBeenCalledTimes(2);
26
+ expect(fn).toHaveBeenCalledWith(3); // Last call's arguments
27
+ });
28
+
29
+ test('throttle with leading: false', () => {
30
+ const fn = vi.fn();
31
+ const throttled = throttle(fn, 100, { leading: false });
32
+
33
+ throttled(1);
34
+ expect(fn).not.toHaveBeenCalled();
35
+
36
+ vi.advanceTimersByTime(100);
37
+ expect(fn).toHaveBeenCalledTimes(1);
38
+ expect(fn).toHaveBeenCalledWith(1);
39
+ });
40
+
41
+ test('throttle with trailing: false', () => {
42
+ const fn = vi.fn();
43
+ const throttled = throttle(fn, 100, { trailing: false });
44
+
45
+ throttled(1);
46
+ expect(fn).toHaveBeenCalledTimes(1);
47
+ expect(fn).toHaveBeenCalledWith(1);
48
+
49
+ throttled(2);
50
+ throttled(3);
51
+ expect(fn).toHaveBeenCalledTimes(1);
52
+
53
+ vi.advanceTimersByTime(100);
54
+ expect(fn).toHaveBeenCalledTimes(1); // No trailing execution
55
+ });
56
+
57
+ test('throttle with leading: false and trailing: false', () => {
58
+ const fn = vi.fn();
59
+ const throttled = throttle(fn, 100, {
60
+ leading: false,
61
+ trailing: false,
62
+ });
63
+
64
+ throttled(1);
65
+ throttled(2);
66
+ throttled(3);
67
+
68
+ expect(fn).not.toHaveBeenCalled();
69
+
70
+ vi.advanceTimersByTime(100);
71
+ expect(fn).not.toHaveBeenCalled();
72
+ });
73
+
74
+ test('throttle cancel', () => {
75
+ const fn = vi.fn();
76
+ const throttled = throttle(fn, 100);
77
+
78
+ throttled(1);
79
+ expect(fn).toHaveBeenCalledTimes(1);
80
+
81
+ throttled(2);
82
+ throttled.cancel();
83
+
84
+ vi.advanceTimersByTime(100);
85
+ expect(fn).toHaveBeenCalledTimes(1); // Trailing call cancelled
86
+ });
87
+
88
+ test('throttle flush', () => {
89
+ const fn = vi.fn();
90
+ const throttled = throttle(fn, 100);
91
+
92
+ throttled(1);
93
+ expect(fn).toHaveBeenCalledTimes(1);
94
+
95
+ throttled(2);
96
+ throttled(3);
97
+ throttled.flush();
98
+
99
+ expect(fn).toHaveBeenCalledTimes(2);
100
+ expect(fn).toHaveBeenCalledWith(3);
101
+
102
+ vi.advanceTimersByTime(100);
103
+ expect(fn).toHaveBeenCalledTimes(2); // Already flushed
104
+ });
105
+
106
+ test('throttle preserves this context', () => {
107
+ const obj = {
108
+ value: 42,
109
+ fn(this: any, arg: number) {
110
+ return this.value + arg;
111
+ },
112
+ };
113
+
114
+ const throttled = throttle(obj.fn, 100);
115
+ throttled.call(obj, 10);
116
+
117
+ expect(obj.value).toBe(42);
118
+ // Function executes with correct context
119
+ });
120
+
121
+ test('throttle multiple calls within wait period', () => {
122
+ const fn = vi.fn();
123
+ const throttled = throttle(fn, 100);
124
+
125
+ throttled(1);
126
+ expect(fn).toHaveBeenCalledTimes(1);
127
+ expect(fn).toHaveBeenCalledWith(1);
128
+
129
+ vi.advanceTimersByTime(50);
130
+ throttled(2);
131
+ expect(fn).toHaveBeenCalledTimes(1); // Still only called once
132
+
133
+ vi.advanceTimersByTime(50);
134
+ // After 100ms total, should execute immediately with latest args
135
+ expect(fn).toHaveBeenCalledTimes(2);
136
+ expect(fn).toHaveBeenCalledWith(2);
137
+
138
+ vi.advanceTimersByTime(50);
139
+ throttled(3);
140
+ expect(fn).toHaveBeenCalledTimes(3);
141
+ expect(fn).toHaveBeenCalledWith(3);
142
+ });
143
+
144
+ test('throttle with leading and trailing both true', () => {
145
+ const fn = vi.fn();
146
+ const throttled = throttle(fn, 100, {
147
+ leading: true,
148
+ trailing: true,
149
+ });
150
+
151
+ throttled(1);
152
+ expect(fn).toHaveBeenCalledTimes(1);
153
+ expect(fn).toHaveBeenCalledWith(1);
154
+
155
+ throttled(2);
156
+ expect(fn).toHaveBeenCalledTimes(1);
157
+
158
+ vi.advanceTimersByTime(100);
159
+ expect(fn).toHaveBeenCalledTimes(2);
160
+ expect(fn).toHaveBeenCalledWith(2);
161
+ });
162
+
163
+ test('throttle rapid successive calls', () => {
164
+ const fn = vi.fn();
165
+ const throttled = throttle(fn, 100);
166
+
167
+ for (let i = 0; i < 10; i++) {
168
+ throttled(i);
169
+ vi.advanceTimersByTime(10);
170
+ }
171
+
172
+ // Should be called multiple times (once per 100ms)
173
+ expect(fn).toHaveBeenCalled();
174
+ expect(fn.mock.calls.length).toBeGreaterThan(1);
175
+ });
176
+
177
+ test('throttle with zero wait time', () => {
178
+ const fn = vi.fn();
179
+ const throttled = throttle(fn, 0);
180
+
181
+ throttled(1);
182
+ expect(fn).toHaveBeenCalledTimes(1);
183
+
184
+ throttled(2);
185
+ vi.advanceTimersByTime(0);
186
+ expect(fn).toHaveBeenCalledTimes(2);
187
+ });
188
+
189
+ test('throttle cancel after flush', () => {
190
+ const fn = vi.fn();
191
+ const throttled = throttle(fn, 100);
192
+
193
+ throttled(1);
194
+ expect(fn).toHaveBeenCalledTimes(1);
195
+
196
+ throttled(2);
197
+ throttled.flush();
198
+ expect(fn).toHaveBeenCalledTimes(2);
199
+
200
+ throttled.cancel();
201
+ vi.advanceTimersByTime(100);
202
+ expect(fn).toHaveBeenCalledTimes(2); // No additional call
203
+ });
204
+
205
+ test('throttle maintains last arguments', () => {
206
+ const fn = vi.fn();
207
+ const throttled = throttle(fn, 100);
208
+
209
+ throttled('first');
210
+ expect(fn).toHaveBeenCalledWith('first');
211
+
212
+ throttled('second');
213
+ throttled('third');
214
+ expect(fn).toHaveBeenCalledTimes(1);
215
+
216
+ vi.advanceTimersByTime(100);
217
+ expect(fn).toHaveBeenCalledTimes(2);
218
+ expect(fn).toHaveBeenCalledWith('third'); // Last call's arguments
219
+ });
220
+
221
+ test('throttle with multiple arguments', () => {
222
+ const fn = vi.fn();
223
+ const throttled = throttle(fn, 100);
224
+
225
+ throttled(1, 'a', true);
226
+ expect(fn).toHaveBeenCalledWith(1, 'a', true);
227
+
228
+ throttled(2, 'b', false);
229
+ throttled(3, 'c', true);
230
+ expect(fn).toHaveBeenCalledTimes(1);
231
+
232
+ vi.advanceTimersByTime(100);
233
+ expect(fn).toHaveBeenCalledTimes(2);
234
+ expect(fn).toHaveBeenCalledWith(3, 'c', true);
5
235
  });