Skip to content

Commit

Permalink
Add .trigger() (#41)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
olafurw and sindresorhus committed May 25, 2024
1 parent 691098b commit 1fe9160
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 22 deletions.
9 changes: 7 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ type AnyFunction = (...arguments_: readonly any[]) => unknown;
/**
Creates a debounced function that delays execution until `wait` milliseconds have passed since its last invocation.
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.
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.
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.
The returned function has the following methods:
- `.clear()` cancels any scheduled executions.
- `.flush()` if an execution is scheduled then it will be immediately executed and the timer will be cleared.
- `.trigger()` executes the function immediately and clears the timer if it was previously set.
*/
declare function debounce<F extends AnyFunction>(
function_: F,
Expand All @@ -18,6 +22,7 @@ declare namespace debounce {
(...arguments_: Parameters<F>): ReturnType<F> | undefined;
clear(): void;
flush(): void;
trigger(): void;
};
}

Expand Down
34 changes: 17 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ function debounce(function_, wait = 100, options = {}) {
let timestamp;
let result;

function run() {
const callContext = storedContext;
const callArguments = storedArguments;
storedContext = undefined;
storedArguments = undefined;
result = function_.apply(callContext, callArguments);
return result;
}

function later() {
const last = Date.now() - timestamp;

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

if (!immediate) {
const callContext = storedContext;
const callArguments = storedArguments;
storedContext = undefined;
storedArguments = undefined;
result = function_.apply(callContext, callArguments);
result = run();
}
}
}
Expand All @@ -50,11 +55,7 @@ function debounce(function_, wait = 100, options = {}) {
}

if (callNow) {
const callContext = storedContext;
const callArguments = storedArguments;
storedContext = undefined;
storedArguments = undefined;
result = function_.apply(callContext, callArguments);
result = run();
}

return result;
Expand All @@ -74,14 +75,13 @@ function debounce(function_, wait = 100, options = {}) {
return;
}

const callContext = storedContext;
const callArguments = storedArguments;
storedContext = undefined;
storedArguments = undefined;
result = function_.apply(callContext, callArguments);
debounced.trigger();
};

clearTimeout(timeoutId);
timeoutId = undefined;
debounced.trigger = () => {
result = run();

debounced.clear();
};

return debounced;
Expand Down
16 changes: 13 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,31 @@ To later clear the timer and cancel currently scheduled executions:
window.onresize.clear();
```

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

```js
window.onresize.flush();
```

To execute immediately and reset the timer if it was previously set:

```js
window.onresize.trigger();
```

## API

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

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

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.
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.

The returned function has the following methods:

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.
- `.clear()` cancels any scheduled executions.
- `.flush()` if an execution is scheduled then it will be immediately executed and the timer will be cleared.
- `.trigger()` executes the function immediately and clears the timer if it was previously set.

## Related

Expand Down
35 changes: 35 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,38 @@ test('calling flush method without any scheduled execution', async () => {

assert.strictEqual(callback.callCount, 0, 'Callback should not be executed if flush is called without any scheduled execution');
});

test('calling the trigger function should run it immediately', async () => {
const clock = sinon.useFakeTimers();
const callback = sinon.spy();
const fn = debounce(callback, 100);

fn();
fn.trigger();

assert.strictEqual(callback.callCount, 1, 'Callback should be called once when using trigger method');

clock.tick(100);

assert.strictEqual(callback.callCount, 1, 'Callback should stay at one call after timeout');

clock.restore();
});

test('calling the trigger should not affect future function calls', async () => {
const clock = sinon.useFakeTimers();
const callback = sinon.spy();
const fn = debounce(callback, 100);

fn();
fn.trigger();
fn();

assert.strictEqual(callback.callCount, 1, 'Callback should be called once when using trigger method');

clock.tick(100);

assert.strictEqual(callback.callCount, 2, 'Callback should total two calls after timeout');

clock.restore();
});

0 comments on commit 1fe9160

Please sign in to comment.