调试
#javascript #面试 #debounce

辩论是一种用于控制我们允许随时间执行函数多少次的技术。当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是想到的第一件事。
我们还需要返回一个围绕回调函数参数的函数。此功能需要做一些事情:

  1. 调试调用

    • 它仅在wait延迟后才调用回调函数。这是使用setTimeout执行的。由于我们可能需要清除计时器,如果在有待处理的调用时再次调用拒绝的函数,我们需要保留对timeoutID的引用,这是setTimeout的返回值。
    • 如果在有待处理的调用时再次调用该函数,我们应该取消现有计时器,并安排使用完整的wait持续时间延迟调用的新计时器。我们可以通过clearTimeout(timeoutID)取消计时器。
  2. 用正确的参数调用回调函数
    拒绝功能与原始功能一样使用,
    因此,我们应该转发此和功能的价值
    调用原始回调函数时的参数。
    您可能很想使用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();
}