辩论是一种用于控制我们允许随时间执行函数多少次的技术。当JavaScript函数以x毫秒的等待时间拒绝时,它必须等到自调用签名函数以来X毫秒经过之后。几乎可以肯定,在进入电梯之前,您在日常生活中遇到了辩论。仅在x不按“开门”按钮(未调用拒绝的功能)之后,电梯门才能真正关闭(回调功能已执行)。
实现了接受回调功能和等待持续时间的访问功能。呼叫debounce()返回一个函数,该函数在上述行为上具有辩论回调函数的调用。
example:
let i = 0;
function increment() {
i++;
}
const throttledIncrement = throttle(increment, 100);
// t = 0: Call throttledIncrement(). i is now 1.
throttledIncrement(); // i = 1
// t = 50: Call throttledIncrement() again.
// i is still 1 because 100ms have not passed.
throttledIncrement(); // i = 1
// t = 101: Call throttledIncrement() again. i is now 2.
// i can be incremented because it has been more than 100ms
// since the last throttledIncrement() call at t = 0.
throttledIncrement(); // i = 2
与油门一起审出是最常见的前端面试问题之一;这是倒二进制树的前端。因此,您应该确保您对这个问题非常熟悉。
解决方案:
鉴于要调用功能之前有一个等待时间,我们知道我们将需要一个计时器,而Settimeout是想到的第一件事。
我们还需要返回一个围绕回调函数参数的函数。此功能需要做一些事情:
-
调试调用
- 它仅在
wait
延迟后才调用回调函数。这是使用setTimeout
执行的。由于我们可能需要清除计时器,如果在有待处理的调用时再次调用拒绝的函数,我们需要保留对timeoutID
的引用,这是setTimeout
的返回值。 - 如果在有待处理的调用时再次调用该函数,我们应该取消现有计时器,并安排使用完整的
wait
持续时间延迟调用的新计时器。我们可以通过clearTimeout(timeoutID)
取消计时器。
- 它仅在
-
用正确的参数调用回调函数
拒绝功能与原始功能一样使用,
因此,我们应该转发此和功能的价值
调用原始回调函数时的参数。
您可能很想使用func(...args)
,但这将是
如果调用回调函数,则会丢失。因此,我们
使用Function.prototype.apply()/Function.prototype.call()
这使我们能够将this
指定为第一个参数。
-
func.apply(thisarg,args)
-
func.call(thisarg,... args)
/**
* @callback func
* @param {number} wait
* @return {Function}
*/
// debounce(func, wait) will returned a debounced function, which delays the invoke.
export default function debounce(func, wait) {
let timer = null;
function debounced (...args) {
const context = this; //retain a reference to this outside the setTimeout and pass it into func.apply as the 1st argument.
if(timer) clearTimeout(timer); //If the function is called again while there's a pending invocation, we should cancel existing timers
//schedule a new timer for the delayed invocation with the full wait duration.
timer=setTimeout(()=>{
func.apply(context, args)
}, wait)
}
return debounced // 注意不要return arrow function
}
更多解决方案
- 返回箭头功能
function debounce(func, wait) {
let timer = null;
// return the arrow function
return (...args) => {
if(timer) clearTimeout(timer);
timer=setTimeout(()=>{
func(args);
}, wait)
}
}
/*TEST:-------------------------------------------------- */
function test (){ console.log('test') }
// 没用debounce时:
document.onmousemove = function(){
test();
}
// 用了debounce:
const debouncedFn = debounce(test, 1000);
document.onmousemove = function(){
debouncedFn();
}