问题
I'm trying to write a debounce function with typescript.
I found an example of it in here. Code follows:
export function debounce<Params extends any[]>(
func: (...args: Params) => any,
timeout: number,
): (...args: Params) => void {
let timer: NodeJS.Timeout
return (...args: Params) => {
clearTimeout(timer)
timer = setTimeout(() => {
func(...args)
}, timeout)
}
}
Problem is:
- Function passed as a parameter is not getting called after the specified timeout
- I can't use lodash or any other external library because I'm trying to avoid adding new dependencies to this project.
Thanks.
回答1:
How do you use your debounce
function? I prepare fiddle, you can check working solution here
function debounce<Params extends any[]>(
func: (...args: Params) => any,
timeout: number,
): (...args: Params) => void {
let timer: NodeJS.Timeout
return (...args: Params) => {
clearTimeout(timer)
timer = setTimeout(() => {
func(...args)
}, timeout)
}
}
function test(message) {
alert(message);
}
const debouncedTest = debounce(test, 2000);
debouncedTest('message');
Well, it's not typescript troubles
回答2:
This is intended as a supplement to Saveli Tomac's excellent answer.
In the comments I said I didn't think that implementation was particularly good. In particular it has two problems:
- It doesn't have an immediate option. Most debounce implementations in the wild (including the one you linked in your question) have this.
- The returned function ignores the
this
value.
Here's an example that fixes these:
const debounce = (n: number, fn: (...params: any[]) => any, immed: boolean = false) => {
let timer: number | undefined = undefined;
return function (this: any, ...args: any[]) {
if (timer === undefined && immed) {
fn.apply(this, args);
}
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), n);
return timer;
}
};
Typescript Playground
回答3:
If the result of the function is useful for you, you can try the extension methods that I wrote for the function interface:
https://gist.github.com/falahati/fda618a9b59bb7d7f33b9ba0d5ef01a3
Usage is as simple as creating a debounce or throttled version of your function by using the trailingDebounce(wait: number)
, leadingDebounce(wait: number)
, trailingThrottle(wait: number)
or the leadingThrottle(wait: number)
function. Here is an example:
class RelativeOffsetCalculator {
public addOffsetTrailingDebounce = this.addOffset.trailingDebounce(500);
public addOffsetLeadingDebounce = this.addOffset.leadingDebounce(500);
public addOffsetTrailingThrottle = this.addOffset.trailingThrottle(500);
public addOffsetLeadingThrottle = this.addOffset.leadingThrottle(500);
private _offset: number;
constructor(offset: number) {
this._offset = offset;
}
public addOffset(base: number): number {
return base + this._offset;
}
}
const instance = new RelativeOffsetCalculator(1);
let executions = 0;
// Call each 100ms for 10 times at a total of a second, should get limited
const intervalTimer = window.setInterval(
() => {
if (executions >= 10) {
window.clearInterval(intervalTimer);
return;
}
instance.addOffsetLeadingDebounce(executions).then(
(result) => console.log(result),
(error) => console.warn(error),
);
executions++;
},
100,
);
// A later call at 2 seconds mark, should not get limited
window.setTimeout(
() => {
instance.addOffsetLeadingDebounce(100).then(
(result) => console.log("Late Execution: ", result),
(error) => console.warn("Late Execution: ", error),
);
},
(10 * 100) + 1000,
);
This results in:
1 1 1 1 1 1 1 1 1 1 Late Execution: 101
,
If the addOffsetTrailingDebounce
function is used, the results are:
10 10 10 10 10 10 10 10 10 10 Late Execution: 101
and if the addOffsetLeadingThrottle
function is used, the results are:
1 1 1 1 1 5 5 5 5 5 Late Execution: 101
and if the addOffsetTraillingThrottle
function is used, the results are:
5 5 5 5 5 10 10 10 10 10 Late Execution: 101
来源:https://stackoverflow.com/questions/59104425/typescript-debounce-function-not-calling-function-passed-as-parameter