Skip to content

Commit 1fe9160

Browse files
olafurwsindresorhus
andauthoredMay 25, 2024··
Add .trigger() (#41)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent 691098b commit 1fe9160

File tree

4 files changed

+72
-22
lines changed

4 files changed

+72
-22
lines changed
 

‎index.d.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ type AnyFunction = (...arguments_: readonly any[]) => unknown;
33
/**
44
Creates a debounced function that delays execution until `wait` milliseconds have passed since its last invocation.
55
6-
Set the `immediate` option to `true` to invoke the function immediately at the start of the `wait` interval, preventing issues such as double-clicks on a button.
6+
Set the `immediate` option to `true` to execute the function immediately at the start of the `wait` interval, preventing issues such as double-clicks on a button.
77
8-
The returned function has a `.clear()` method to cancel scheduled executions, and a `.flush()` method for immediate execution and resetting the timer for future calls.
8+
The returned function has the following methods:
9+
10+
- `.clear()` cancels any scheduled executions.
11+
- `.flush()` if an execution is scheduled then it will be immediately executed and the timer will be cleared.
12+
- `.trigger()` executes the function immediately and clears the timer if it was previously set.
913
*/
1014
declare function debounce<F extends AnyFunction>(
1115
function_: F,
@@ -18,6 +22,7 @@ declare namespace debounce {
1822
(...arguments_: Parameters<F>): ReturnType<F> | undefined;
1923
clear(): void;
2024
flush(): void;
25+
trigger(): void;
2126
};
2227
}
2328

‎index.js

+17-17
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ function debounce(function_, wait = 100, options = {}) {
1616
let timestamp;
1717
let result;
1818

19+
function run() {
20+
const callContext = storedContext;
21+
const callArguments = storedArguments;
22+
storedContext = undefined;
23+
storedArguments = undefined;
24+
result = function_.apply(callContext, callArguments);
25+
return result;
26+
}
27+
1928
function later() {
2029
const last = Date.now() - timestamp;
2130

@@ -25,11 +34,7 @@ function debounce(function_, wait = 100, options = {}) {
2534
timeoutId = undefined;
2635

2736
if (!immediate) {
28-
const callContext = storedContext;
29-
const callArguments = storedArguments;
30-
storedContext = undefined;
31-
storedArguments = undefined;
32-
result = function_.apply(callContext, callArguments);
37+
result = run();
3338
}
3439
}
3540
}
@@ -50,11 +55,7 @@ function debounce(function_, wait = 100, options = {}) {
5055
}
5156

5257
if (callNow) {
53-
const callContext = storedContext;
54-
const callArguments = storedArguments;
55-
storedContext = undefined;
56-
storedArguments = undefined;
57-
result = function_.apply(callContext, callArguments);
58+
result = run();
5859
}
5960

6061
return result;
@@ -74,14 +75,13 @@ function debounce(function_, wait = 100, options = {}) {
7475
return;
7576
}
7677

77-
const callContext = storedContext;
78-
const callArguments = storedArguments;
79-
storedContext = undefined;
80-
storedArguments = undefined;
81-
result = function_.apply(callContext, callArguments);
78+
debounced.trigger();
79+
};
8280

83-
clearTimeout(timeoutId);
84-
timeoutId = undefined;
81+
debounced.trigger = () => {
82+
result = run();
83+
84+
debounced.clear();
8585
};
8686

8787
return debounced;

‎readme.md

+13-3
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,31 @@ To later clear the timer and cancel currently scheduled executions:
2929
window.onresize.clear();
3030
```
3131

32-
To execute any pending invocations and reset the timer:
32+
To execute immediately only if you have scheduled invocations and reset the timer:
3333

3434
```js
3535
window.onresize.flush();
3636
```
3737

38+
To execute immediately and reset the timer if it was previously set:
39+
40+
```js
41+
window.onresize.trigger();
42+
```
43+
3844
## API
3945

4046
### debounce(fn, wait, options?)
4147

4248
Creates a debounced function that delays execution until `wait` milliseconds have passed since its last invocation.
4349

44-
Set the `immediate` option to `true` to invoke the function immediately at the start of the `wait` interval, preventing issues such as double-clicks on a button.
50+
Set the `immediate` option to `true` to execute the function immediately at the start of the `wait` interval, preventing issues such as double-clicks on a button.
51+
52+
The returned function has the following methods:
4553

46-
The returned function has a `.clear()` method to cancel scheduled executions, and a `.flush()` method for immediate execution and resetting the timer for future calls.
54+
- `.clear()` cancels any scheduled executions.
55+
- `.flush()` if an execution is scheduled then it will be immediately executed and the timer will be cleared.
56+
- `.trigger()` executes the function immediately and clears the timer if it was previously set.
4757

4858
## Related
4959

‎test.js

+35
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,38 @@ test('calling flush method without any scheduled execution', async () => {
397397

398398
assert.strictEqual(callback.callCount, 0, 'Callback should not be executed if flush is called without any scheduled execution');
399399
});
400+
401+
test('calling the trigger function should run it immediately', async () => {
402+
const clock = sinon.useFakeTimers();
403+
const callback = sinon.spy();
404+
const fn = debounce(callback, 100);
405+
406+
fn();
407+
fn.trigger();
408+
409+
assert.strictEqual(callback.callCount, 1, 'Callback should be called once when using trigger method');
410+
411+
clock.tick(100);
412+
413+
assert.strictEqual(callback.callCount, 1, 'Callback should stay at one call after timeout');
414+
415+
clock.restore();
416+
});
417+
418+
test('calling the trigger should not affect future function calls', async () => {
419+
const clock = sinon.useFakeTimers();
420+
const callback = sinon.spy();
421+
const fn = debounce(callback, 100);
422+
423+
fn();
424+
fn.trigger();
425+
fn();
426+
427+
assert.strictEqual(callback.callCount, 1, 'Callback should be called once when using trigger method');
428+
429+
clock.tick(100);
430+
431+
assert.strictEqual(callback.callCount, 2, 'Callback should total two calls after timeout');
432+
433+
clock.restore();
434+
});

0 commit comments

Comments
 (0)
Please sign in to comment.