节流和解封函数之间的区别

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

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

http://remysharp.com/2010/07/21/throttling-function-calls < a href = " http://remysharp.com/2010/07/21/throttling-function-calls " > < / >

http://benalman.com/projects/jquery-throttle-debounce-plugin/ < a href = " http://benalman.com/projects/jquery-throttle-debounce-plugin/ " > < / >

166928 次浏览

简单来说:

  • 节流将延迟执行函数。它将减少多次触发事件的通知。
  • 消除抖动将对一个函数的一系列连续调用组合成对该函数的单个调用。它确保为多次触发的事件发出一个通知。

你可以直观地看到区别在这里

如果你有一个函数被调用了很多次——例如当一个调整大小或鼠标移动事件发生时,它可以被调用很多次。如果你不想要这种行为,你可以节气门它,这样函数就会定期被调用。消除抖动将意味着它在一系列事件的结束(或开始)时被调用。

消除抖动允许你管理一个函数可以接收的调用频率。它将发生在给定函数上的多个调用组合在一起,以便忽略在特定时间持续时间到期之前发生的重复调用。从根本上说,deboundation确保了一个可能发生多次的事件只发送了一个信号。

节流将函数接收的调用频率限制在固定的时间间隔内。它用于确保目标函数的调用频率不会超过指定的延迟。节流是降低重复事件的速率。

我个人觉得防反跳节气门更难理解。

因为这两个函数都可以帮助您延迟和降低某些执行的速度。假设您正在调用由throttle/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秒发送一条新消息,而你的即时通讯应用程序图标上下跳动,你可以…

  • 天真的方法:检查每一个消息,只要它到达。当你的应用程序图标反弹时,检查。这不是最有效的方法,但你总是最新的。
  • 节气门方法:你每5分钟检查一次(当有新的)。当新消息到来时,如果你在过去5分钟内检查过,请忽略它。使用这种方法可以节省时间,同时仍然处于循环中。
  • 防反跳方法:你知道Chatty,她把整个故事分解成碎片,在一个接一个的消息中发送。你等待Chatty完成整个故事:如果她停止发送消息5分钟,你会认为她已经完成了,现在你检查所有。

通俗地说:

消除抖动将阻止仍然被频繁调用的函数运行。一个debound函数只会在确定它不再被调用时运行,此时它只会运行一次。脱绳的实际例子:

  • 如果用户“停止输入”,自动保存或验证文本字段的内容:该操作只会执行一次,在确定用户不再输入(不再按键)之后

  • 记录用户休息鼠标的位置:用户不再移动鼠标,因此可以记录(最后)位置

节流只会阻止最近运行过的函数运行,不管调用频率如何。节流的实际例子:

  • v-sync的实现是基于节流的:从上一次绘制屏幕到现在已经过去了16ms,屏幕才会被绘制。无论调用多少次屏幕刷新功能,它最多只能每16毫秒运行一次。

lodash库建议使用下面的文章https://css-tricks.com/debouncing-throttling-explained-examples/,其中详细解释了DebounceThrottle之间的区别及其起源

节流强制一个函数在一段时间内可以被调用的最大次数。就像“最多每100毫秒执行一次这个函数。”

消除抖动强制函数不被再次调用,直到经过一定的时间而没有被调用。就像“仅在100毫秒后未被调用时才执行该函数。”

ref

throtle只是防反跳的包装器,它使防反跳在一段时间内调用传递的function,如果防反跳延迟一个函数调用的时间大于throtle中指定的时间。

差异

+--------------+-------------------+-------------------+
|              |  Throttle 1 sec   |  Debounce 1 sec   |
+--------------+-------------------+-------------------+
| Delay        | no delay          | 1 sec delay       |
|              |                   |                   |
| Emits new if | last was emitted  | there is no input |
|              | before 1 sec      |  in last 1 sec    |
+--------------+-------------------+-------------------+

用例解释:

  • 搜索栏,不想每次用户按下键搜索?当用户停止输入1秒时想要搜索。使用debounce 1

    .

    .
  • 手枪每次射击之间需要1秒的时间,但用户多次点击鼠标。使用throttle鼠标点击。

角色互换 .:

  • 在搜索栏上节流1秒-如果用户用0.6 sec中的每个字符输入abcdefghij。然后油门将触发第a按下。它将在接下来的1秒内忽略每一次按压,即bat .6秒将被忽略。然后在1.2秒时c将再次触发,再次重置时间。因此d将被忽略,而e将被触发。

  • 当用户看到一个敌人,他点击鼠标,但它不会射击。他将在这一秒内再次点击几次,但它不会射击。他将查看它是否还有子弹,那时(最后一次点击后1秒)手枪将自动射击。

进一步解释投入产出与现实生活的比较

酒吧外面有几个警卫。卫兵允许说“我要去”的人;让他进入酒吧。这是正常的情况。任何人说“我要去”;被允许进入酒吧。

现在有一个节流警卫 (节流5秒)。他喜欢最先回应的人。任何说“我要去”的人;首先,他允许那个人。然后他拒绝了每一个人5秒。在那之后,同样,任何人先说它将被允许,其他人将被拒绝5秒

还有另一个防反跳警卫 (反弹5秒)。他喜欢能让他精神放松的人。所以如果有人说“我会去”,警卫等待5秒。如果5秒钟内没有其他人打扰他,他会允许第一个人打扰他。如果别人说“我会去”;在那些5秒中,他拒绝了第一个。他再次开始5秒等待第二个人,看看第二个人是否能给他带来精神上的休息。

这很简单。

它们执行完全一样(速率限制),但当节气门被调用时,它会周期性地触发你的函数,而防反跳只在结束时触发一次。

例子:如果你正在滚动,throttle将在你滚动时缓慢地调用你的函数(每X毫秒一次)。Debounce将一直等到滚动完成调用函数之后。

--

我喜欢将节流视为“包括debounce"”,他们都在事件完成后做出最终决定,但由于实现细节,两者并不总是在同一时间做出最终决定,这可能会使演示令人困惑。

据我所知,简单来说 节流-类似于调用setInterval(回调)的特定次数,即在事件发生的时间内调用同一函数的特定次数 和. . deboundation -类似于调用setTImeout(callbackForApi)或在事件发生后经过一定时间后调用函数。 这个链接很有用 https://css-tricks.com/the-difference-between-throttling-and-debouncing/ < / p >

你好,我是一个机器人。只要你一直打我,我就会继续和你说话,但每次一秒后。如果你在一秒之前ping我的回复,我仍然会在1秒的间隔内回复你。换句话说,我就是喜欢隔一定的时间间隔回复。

嗨,我是那个^^机器人的表弟。只要你继续ping我,我将保持沉默,因为我喜欢在1秒钟后才回复从你上次联系我开始。我不知道,是因为我的态度有问题还是因为我不喜欢打断别人。换句话说,如果您在上次调用后的1秒内一直向我请求回复,您将永远不会得到回复。是的是的…去吧!说我粗鲁就好。


我是一台伐木机。我将系统日志发送到我们的后端服务器,每隔10分钟。

嗨,我不是那台伐木机的堂兄。(并不是每个防反跳都与这个想象世界中的节流器相关)。我在附近一家餐馆当服务员。我应该让你知道,只要你一直在你的订单中添加东西,我就不会去厨房执行你的订单。只有当10秒过去在你上次修改订单之后,我将假设你完成了你的订单。到那时我才会去厨房执行您点的菜。


酷演示:https://css-tricks.com/debouncing-throttling-explained-examples/

服务员类比的功劳:https://codeburst.io/throttling-and-debouncing-in-javascript-b01cad5c8edf

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

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

防反跳的用例:

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

节气门的用例:

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

节流

节流强制一个函数可以被调用的最大次数 加班。就像“每100次执行一次这个函数 毫秒。”假设在正常情况下你会这样做 在10秒内运行1000次。如果你把它控制在一次 每100毫秒,它最多只执行该函数100次 * < / p >

(10s * 1,000) = 10,000ms
10,000ms / 100ms throttling = 100 maximum calls

消除抖动

debounound强制函数在a之前不被再次调用 一段时间过去了,它还没有被调用。就像在 “只有在100毫秒之后才执行这个函数 被称为。" < / p >

也许一个函数在短时间内被调用1000次,分散在3秒内,然后停止被调用。如果您在100毫秒时将其解除,则该函数只会在爆发结束后的3.1秒内触发一次。每次在爆发期间调用该函数时,它都会重置反弹计时器

来源:节流和脱绳

假设我们有一个回调函数“cb”在事件“E”被调用。 让“E”在1秒内被触发1000次,因此会有1000次对“cb”的调用。也就是1个电话/毫秒。为了优化,我们可以使用:

  • 节流:当节流为(100ms)时,“cb”将是 在第100毫秒,第200毫秒,第300毫秒,…1000 ms)。即1 call/100 ms. 这里对“cb”的1000次调用优化为10次调用。
  • 消除抖动:当debouning为(100ms)时,“cb”将只在[1100秒]被调用一次。这是发生在第1000毫秒的最后一次触发“E”后的100毫秒。这里对“cb”的1000次调用优化为1次调用。

消除抖动使得函数只能在最后一次调用后的一定时间后执行

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()

这篇文章解释得很好,也有图形。

https://css-tricks.com/debouncing-throttling-explained-examples/

从文章中(并进行了一些澄清):

这(节流)和deboundation之间的主要区别在于节流保证了函数的定期执行,至少每X毫秒执行一次。

通常debounce在指定时间结束时调用函数,而throttle在第一次调用节流函数时调用。有时debounce可以采取额外的配置,将此更改为在开始时执行调用。当使用特定的配置调用时,debounce的一些实现实际上可以做油门所做的事情(参见Lodash源代码)。

对于典型用例的例子,我推荐@Guy的回答。但对我来说,理解这两个概念的最好方法是把它和披萨联系起来。🍕

假设你是一个很棒的披萨师,所以顾客在你的店里不断地要求更多的披萨。

< >强节流: 你决定在每个小时的最后只送出一个披萨,只要你在这个小时内至少收到一个披萨的请求

您在一小时内收到100个披萨请求,因此您在该小时结束时提供一个披萨。然后,你在接下来的一个小时里没有收到披萨的请求,所以你就不会发出披萨了。在接下来的一个小时里,你会收到10个披萨请求,所以你会在那个小时结束的时候发出一个披萨。

< >强消除抖动: 你对你的顾客总是要披萨感到恼火,所以你决定只有在他们停止向你要披萨整整一分钟后才给他们披萨

他们会连续30分钟要披萨,但一分钟后就不再要了。那时,你会给他们一个披萨。

然后他们会连续5分钟要披萨,一分钟后就不再要求了。这时,你再给他们一个披萨。

这实际上是限制一个事件的方法。例如,如果你正在监听onclick事件,如果它是常规的,它将监听你所做的每一次点击。

如果你使用Throttle,它会在你想要监听事件的时间之间设置一个间隔,例如每秒钟监听一次点击。

Debounce的限制更大,它只会在事件开始或结束时触发自己。例如,你正在滚动,你使用Debounce,它只会在你开始和结束滚动时触发。

防反跳:

如果函数没有在间隔内被调用,则在间隔后执行函数。

节流:

以固定的时间间隔执行函数n次。

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

enter image description here

防反跳delay是等待,直到没有更多的调用,然后调用它。就像关闭电梯门一样:门必须等到没有人试图进入时才能关闭。

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


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

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,存储最后一个调用参数,并设置一个间隔来触发,直到没有过去的调用。

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

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

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

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

防反跳,写一个简单的代码输入文本标签搜索一些数据从服务器。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)
}
}

如何调用:用节气门防反跳包装函数来检查差异

__abc0ex:同一按钮点击超过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

一幅图胜过千言万语

< p >节流 Throttle < / p > < p >防反跳 Debounce < / p >

注意防反跳直到事件流停止才会触发。但是,节气门将在每个间隔时间触发一个事件。

(感谢css技巧)

消除抖动节流之间的主要区别是,debounce在用户未在特定时间内执行事件时调用函数,而throttle在用户执行事件时以指定时间间隔调用函数。

如何debound工作在硬件。

去噪是从数字信号中去除噪声的过程。当一个按钮被按下时,信号反弹会导致该按钮被注册为被按了多次。反弹消除了这种噪音,因此按钮只被记录为被按下一次。想象一把尺子在桌子边上弹跳,再想象开关里的金属触点像这样弹跳。

.

更好的是,看看这张图,显示了由弹跳引起的开关噪声。

.

我们使用正确计算额定值的电阻和电容器来平滑n ms的信号。

解释信号节流如何在硬件中工作。

信号节流是限制信号注册次数的过程。这通常用于防止一个按钮被注册为在短时间内被多次按下。

我更喜欢“门控”这个词,但那是因为我从事电子音乐制作。

我们在每个节流阀周期结束时打开闸门,并允许信号通过,然后再次关闭闸门,为下一个节流阀周期。

解释如何debounging工作在软件。

软件中的debound通常是通过使用定时器来实现的。当按钮被按下时,计时器开始。如果在计时器到期前再次按下按钮,计时器将被重置。这确保了按钮只能注册为每个弹跳周期被按下一次。

在debounce的许多实现中,我们创建了函数的debounce版本,该版本嵌入到包含计时器(或门)的闭包中。当计时器延迟过期时,我们再次将其设置为空。实际函数只在计时器为空时运行。通常,这意味着当我们第一次调用debpublished函数时,它将运行一次,然后对它的后续调用将有效地取消,直到延迟时间结束。

在debounce的某些实现中,当调用流被触发且计时器未过期时,计时器将重新启动。仅在反弹停止后调用该函数。这通常被称为尾随反弹。

解释在软件中节流是如何工作的。

软件中的节流通常是通过使用计数器来完成的。当按下按钮时,计数器增加。如果在计数器达到某一阈值之前再次按下按钮,计数器将复位。这限制了在给定的时间内按钮可以被注册为被按下的次数。最好把它想象成一个脉冲或节拍,当呼叫被发送到油门时,它会打开和关闭一个门。

速率限制是考虑节流阀的另一种方式。

为什么这是造成困惑的常见原因?

在许多用例中,debounce或throttle将为您带来您想要的结果,特别是如果您正在使用的软件实现允许您链接、跟踪或引导您的throttle / debounce。

尽管如此,我希望这里所有的答案和这个问题都能帮助你更清楚地理解。

它们非常相似。

消除抖动节流是从一系列事件中选择目标以达到减少目标的目的。它们都需要一段时间作为参数,例如:x ms,和trailing / leading variety来定义如何选择。

消除抖动

当在下一个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 -你跳过所有传入的动作,除了最后一个(“最后一个”是由你为Debounce函数设置的“等待”时间周期定义的,例如,2s -它将认为动作泛滥停止,如果2s内没有采取任何动作,然后它将做出反应。如果你不关心定期更新,这个策略是合理的,你只需要做出至少一次反应。
  • 节流——如果你想“按时”做出反应,即使动作泛滥是无止境的,也要定期更新,你让你的函数定期运行(不是更频繁,而是指定的时间间隔),例如2s节流意味着如果动作被执行,你的响应将被执行一次,但不少于2秒。所以在连续动作泛滥的情况下,你的响应会在0秒、2秒、4秒、6秒、8秒……