谁能给我一个简单的解释,关于节流和debounging函数之间的区别,以限制速率的目的。

在我看来,两者的作用是一样的。我查看了这两个博客来找出答案:

http://remysharp.com/2010/07/21/throttling-function-calls

http://benalman.com/projects/jquery-throttle-debounce-plugin/


当前回答

这里真正重要的是,用最简单的话说:如果你有一些连续重复一段时间的操作(如鼠标移动,或页面大小调整事件),你需要运行一些函数来响应,但你不想对每个操作都做出反应(因为这可能会损害性能),你有两个选择:

debounce - you skip all incoming actions, except the last one (the 'last one' is defined by the 'wait' time period you set for debounce function, for example, 2s - it will consider that actions flood stopped, if no actions were taken for 2s, and then it will react. This strategy is reasonable if you don't care about regular updates, you just need to react at least once. throttle - if you want to react 'on schedule', to make regular updates even if actions flood is endless, you make your function run at regular intervals (no more often, then the specified time interval), for example 2s throttling will mean that your response will be executed an once if action is taken, but no less then 2s after that. So with continuous actions flood your response will be run on 0s, 2s, 4s, 6s, 8s...

其他回答

我个人认为反弹比油门更难理解。

因为这两个函数都可以帮助您延迟和降低某些执行的速度。假设您正在调用由throttle/debounce反复返回的装饰函数…

节流:在指定的时间段内,原函数最多被调用一次。 Debounce:在指定的时间后,调用方停止调用被修饰的函数后,将调用原始函数。

我发现debounce的最后一部分对于理解它试图实现的目标至关重要。我还发现_.debounce的旧版本实现有助于理解(由https://davidwalsh.name/function-debounce提供)。

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    var later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
};

这是一个牵强的比喻,但也许也有帮助。

你有一个叫Chatty的朋友,他喜欢通过IM和你聊天。假设当她说话时,她每5秒发送一条新消息,而你的即时通讯应用程序图标上下跳动,你可以…

Naive approach: check every message as long as it arrives. When your app icon bounces, check. It's not the most effective way, but you are always up-to-date. Throttle approach: you check once every 5 minutes (when there are new ones). When new message arrives, if you have checked anytime in the last 5 minutes, ignore it. You save your time with this approach, while still in the loop. Debounce approach: you know Chatty, she breaks down a whole story into pieces, sends them in one message after another. You wait until Chatty finishes the whole story: if she stops sending messages for 5 minutes, you would assume she has finished, now you check all.

lodash库建议以下文章https://css-tricks.com/debouncing-throttling-explained-examples/详细解释Debounce和Throttle之间的区别及其起源

将debounce和throttle放在一起可能会非常令人困惑,因为它们都共享一个称为延迟的参数。

防反跳。延迟是等到不再有调用时,再调用它。就像关闭电梯门一样:门必须等到没有人试图进入时才能关闭。

节流。延迟是以一定的频率等待,然后调用最后一个。很像手枪射击,枪只是不能超过一定的射速。


让我们看一看实现的细节。

function debounce(fn, delay) {
  let handle = null
  
  return function () {
    if (handle) {
      handle = clearTimeout(handle)
    }
    
    handle = setTimeout(() => {
      fn(...arguments)
    }, delay)
  }
}

Debounce,继续中断超时,直到不再中断为止,然后触发fn。

function throttle(fn, delay) {
  let handle = null
  let prevArgs = undefined
  
  return function() {
    prevArgs = arguments
    if (!handle) {
      fn(...prevArgs)
      prevArgs = null
      handle = setInterval(() => {
        if (!prevArgs) {
          handle = clearInterval(handle)
        } else {
          fn(...prevArgs)
          prevArgs = null
        }
      }, delay)
    }
  }
}

Throttle,存储最后一个调用参数,并设置一个间隔来触发,直到没有过去的调用。

相似之处。它们都有延迟时间,并且在延迟期间不会发生火灾,特别是当只有一场火灾时。两者都不聚合过去的事件,因此事件的数量可能与实际的火灾不同。

的区别。在有重复事件的弹跳情况下,延迟可以延长。而在节流阀情况下的延迟是固定的。所以一般来说,油门产生的火焰比反弹产生的火焰要多。

很容易记住。将组捆绑为一个。节流保持捆绑调用在一定的频率。

更新1-20-23

Throttle可能不需要setInterval,这是我最近写的一个新版本,它也照顾到了这个问题。

function throttle(fn, delay) {
  let canFire = true
  let queue = []

  function pop() {
    if (queue.length < 1) return 

    const [that, args] = queue.pop()
    fn.apply(that, args)
    canFire = false
    setTimeout(() => {
      canFire = true
      pop()
    }, delay)
  }
  
  function push() {
    queue.push([this, arguments])
    if (canFire) pop()
  } 

  push.cancel = () => {
    queue = []
  }

  return push
}

一个现实生活中的类比帮助我记住:

谈话结束。你等对方说完再回答。 鼓形钻头。你只在简单的4/4鼓位上演奏音符。

debounce的用例:

打字。你想在用户停止输入后做一些事情。所以在最后一次击键后等待1秒是有意义的。每次击键重新启动等待。 动画。当用户停止将鼠标悬停在某个元素上时,需要将其收缩。不使用debounce可能会导致不稳定的动画,因为光标会无意中在“热”和“冷”区域之间移动。

节流的用例:

滚动。你想要对滚动做出反应,但限制所做的计算量,所以每100毫秒做一些事情就足以防止潜在的延迟。 鼠标移动。与滚动相同,但用于鼠标移动。 API调用你想在某些UI事件上触发API调用,但想限制API调用的数量,以免使服务器过载。

这里真正重要的是,用最简单的话说:如果你有一些连续重复一段时间的操作(如鼠标移动,或页面大小调整事件),你需要运行一些函数来响应,但你不想对每个操作都做出反应(因为这可能会损害性能),你有两个选择:

debounce - you skip all incoming actions, except the last one (the 'last one' is defined by the 'wait' time period you set for debounce function, for example, 2s - it will consider that actions flood stopped, if no actions were taken for 2s, and then it will react. This strategy is reasonable if you don't care about regular updates, you just need to react at least once. throttle - if you want to react 'on schedule', to make regular updates even if actions flood is endless, you make your function run at regular intervals (no more often, then the specified time interval), for example 2s throttling will mean that your response will be executed an once if action is taken, but no less then 2s after that. So with continuous actions flood your response will be run on 0s, 2s, 4s, 6s, 8s...