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

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

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

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


当前回答

debound使函数只能在最后一次调用后的一段时间后执行

function debounce(func,wait){
  let timeout
  return(...arg) =>{
    clearTimeout(timeout);
    timeout= setTimeout(()=>func.apply(this,arg),wait)
  }
}


function SayHello(){
  console.log("Jesus is saying hello!!")
}


let x = debounce(SayHello,3000)
x()

节流模式限制了在一段时间内可以调用给定事件处理程序的最大次数。它允许以指定的时间间隔周期性地调用处理程序,忽略该等待期结束之前发生的每个调用。

function throttle(callback, interval) {
  let enableCall = true;

  return (...args)=> {
    if (!enableCall) return;

    enableCall = false;
    callback.apply(this, args);
    setTimeout(() => enableCall = true, interval);
  }
}


function helloFromThrottle(){
  console.log("Jesus is saying hi!!!")
}

const foo = throttle(helloFromThrottle,5000)
foo()

其他回答

debound使函数只能在最后一次调用后的一段时间后执行

function debounce(func,wait){
  let timeout
  return(...arg) =>{
    clearTimeout(timeout);
    timeout= setTimeout(()=>func.apply(this,arg),wait)
  }
}


function SayHello(){
  console.log("Jesus is saying hello!!")
}


let x = debounce(SayHello,3000)
x()

节流模式限制了在一段时间内可以调用给定事件处理程序的最大次数。它允许以指定的时间间隔周期性地调用处理程序,忽略该等待期结束之前发生的每个调用。

function throttle(callback, interval) {
  let enableCall = true;

  return (...args)=> {
    if (!enableCall) return;

    enableCall = false;
    callback.apply(this, args);
    setTimeout(() => enableCall = true, interval);
  }
}


function helloFromThrottle(){
  console.log("Jesus is saying hi!!!")
}

const foo = throttle(helloFromThrottle,5000)
foo()

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

因为这两个函数都可以帮助您延迟和降低某些执行的速度。假设您正在调用由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.

debounging和Throttling是从一系列事件中选择目标以达到减少目标的目的。它们都需要一段时间作为参数,例如:x ms,以及后面/前面的变量来定义如何选择。

消除抖动

当x毫秒后没有其他事件发生时,选择事件

"--->": timeline  "o": event  "|===|": period (x=5)

--oo-o-----ooo-o----o-oo--oo-----o-o-ooo------> events
  |===|    |===|    |===|        |===|
  ||===|   ||===|   | |===|      | |===|   
  |  |===| | |===|  |  |===|     |   |===|
  |      | |   |===||     |===|  |    |===|
  |      | |       ||      |===| |     |===|
---------o---------o-----------o-----------o--> selected events (trailing)
--o--------o--------o------------o------------> selected events (leading)

节流

当有事件发生时,每x毫秒选择一个事件

"--->": timeline  "o": event  "|===|": period (x=5)

--oo-o-----ooo-o----o-oo--oo-----o-o-ooo------> events
  |===|    |===|    |===| |===|  |===||===|
------o--------o--------o-----o------o----o---> selected events (trailing)
--o--------o--------o-----o------o----o-------> selected events (leading)

节流阀的简单概念是在表单中频繁点击提交按钮,我们需要使用节流阀。因此提交功能可以防止频繁点击。它将相同的请求保存到函数中。

关于debounce,编写了一个简单的带有输入文本标签的代码,用于从服务器上搜索一些数据。Oninput使用debounce删除之前的请求,并将最后输入的单词传递给服务器

const throttle = (callback, time = 0) => {
    let throttle_req, count = 0;
     return async function () {
         var context = this, args = arguments;  
         if(throttle_req) return;  
         throttle_req = true; 
         if(time > 0)
         {
             callback.apply(context, args); 
             setTimeout(() => {
              throttle_req = false; 
             }, time || 200) 
         }
         else
         {
           let response = await callback.apply(context, args); 
            throttle_req = false; 
           return response;
         } 
     }
  }
const debounce = (callback, time = 0) => {
    let debounce_req;
    return function () {
        var context = this, args = arguments;
        clearTimeout(debounce_req) 
        debounce_req = setTimeout(() => {
             debounce_req = null;
             callback.apply(context, args);
        }, time || 200) 
    }
}

我们如何调用:只是用节流或debounce包装你的函数来检查差异

节流阀:同一按钮点击超过1次

var throttleFunct = throttle(function(num) {
  console.log(num, "hello throttle")
}, 2000);
throttleFunct(300) //it execute. because its the first call
throttleFunct(400) //it won't execute

节流异步没有时间

var getDataAsync =  throttle(function(id, name) {
    return new Promise((resolve) => {  
      setTimeout(() => {
            resolve({name: name, id: id})
      }, 2000)
     }) 
});
async function test() {
let response = await getDataAsync(120, 'Sherley').then(resp => resp)  
console.log(response, "respond") //it execute. because its the first call
response = await getDataAsync(120, 'James').then(resp => resp)  
console.log(response, "respond2")//it executes 2 after first request
response = await getDataAsync(120, 'Jonathan').then(resp => resp)  
console.log(response, "respond3")//it executes 3 after second request
    }
    test()

例如:搜索框自动完成

var debounceFunct = debounce(function(num) {
  console.log(num+1)
}, 2000);
debounceFunct(300) //it won't execute and it cancelled
debounceFunct(400) // it executes and it replaced with the previous call. because this is the latest event fire

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

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