节流阀每个等待时间最多执行一次功能吗?

时间:2019-05-13 21:17:32

标签: javascript lodash

我想每100毫秒限制一次我的功能。在下面的代码中,我希望仅打印1和3。但是实际结果中还会打印2。

function say(what) {
  console.log(what);
}

const t = _.throttle(say, 100);

setTimeout(() => {
  t(1);
}, 50);
setTimeout(() => {
  t(1);
}, 50);
setTimeout(() => {
  t(1);
}, 50);
setTimeout(() => {
  t(1);
}, 55);
setTimeout(() => {
  t(2);
}, 55);
setTimeout(() => {
  t(3);
}, 500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.1/lodash.js"></script>

我必须将油门等待时间更改为500,以滤除2。

也许我对油门的理解是错误的。节流阀是否应该在每个等待时间内最多执行一次该功能?

3 个答案:

答案 0 :(得分:4)

您对如何使用此油门设置的理解不太正确。

直接回答:

  

每个等待周期内节气门最多执行一次该功能吗?

在未传递任何选项的情况下,如果在该时间段内多次调用了节流功能,则节流将在等待时间段的开始和结束(两次)执行。

在50ms处,您的第一个函数被调用,并且“ throttle”立即运行它,这时您的下一个f(1)也被排队等待在100ms处被调用。但是然后调用了另一个f(1),又调用了另一个f(1)然后调用了f(2),并且每个新变量都将最后一个替换为要在100ms处调用的函数(这是您进入油门的时间) )。然后经过100毫秒,然后在适当的时候调用f(3)或多或少。

如果您没有将任何选项传递给_.throttle,它将立即调用第一个函数运行(0毫秒),然后在设置的时间段内调用最后一个函数运行。

以@zfrisch的代码作为开始:

function say(what) {
  console.log(what);
}

const t = _.throttle(say, 100);
const TO = (n, i) => setTimeout(() => {
  t(n);
}, i);

TO(1, 50); // logged immediately
TO(1, 50);
TO(1, 50);
TO(1, 55);
TO(2, 55); // logged at 100ms (as it was the last function attempted)
function say(what) {
  console.log(what);
}

const t = _.throttle(say, 100, { leading: false });
const TO = (n, i) => setTimeout(() => {
  t(n);
}, i);

TO(1, 50); // not logged at all
TO(1, 50);
TO(1, 50);
TO(1, 55);
TO(2, 55); // logged at 100ms (as it was the last function attempted)
function say(what) {
  console.log(what);
}

const t = _.throttle(say, 100, { trailing: false });
const TO = (n, i) => setTimeout(() => {
  t(n);
}, i);

TO(1, 50); // logged immediately
TO(1, 50);
TO(1, 50);
TO(1, 55);
TO(2, 55); // not logged at all

答案 1 :(得分:3)

节气门将延迟执行等待时间,但仍会调用该函数。在您的示例中,将发生以下情况:脚本启动后50毫秒记录了第一个1,此时节流阀将开始计数100毫秒。在此期间对t的任何呼叫都将被延迟。经过100毫秒后,将触发对t的最后一次调用。再过100ms,t不被调用,因此什么也没发生,最后一次调用发生了。

答案 2 :(得分:1)

问题:

很容易看到您假设代码将如何工作。理解它并不是一件难事,但之所以没有按照您期望的方式执行,是因为该函数的默认行为。

Throttle函数:

Throttle Parameters

从上面您可以看到Throttle花费了functionwait时间(以毫秒为单位)作为其前两个参数,但是options在您的当前的代码,这些是解决问题的关键。


选项:

_.throttle具有选项leadingtrailing。这两个默认都设置为true

不幸的是,除非您熟悉幕后的过程,否则命名的选项尽管很恰当,但仅凭其名称并不是很明确。


说明:

leading 是指在适用时间调用的那些。这些是:

  • 初始通话
  • 下次通话 100ms
  • 下一个呼叫之后再过100ms

trailing 是指在时间间隔内进行的throttle函数的最后一次调用。此函数不是简单地废弃,而是推迟到可以调用 为止。将其视为可在间隔期间填充的插槽。在间隔期间进行呼叫时,该插槽将被新功能填充/替换。

这可以说明:

  • 已发起呼叫
  • 在间隔期间用function 1进行呼叫
  • 在间隔时间内用function 2进行呼叫
  • function 2取代function 1作为尾随功能
  • 100ms function 2运行。

以下是一个重要概念,并且最终是代码中所发生问题的症结所在:

如果两个选项均为true,则在间隔期间进行跟踪的功能将称为之前新的引导调用throttle函数。

因此,在下一个时间间隔结束时,新的 leading 调用将成为 trailing 调用。

我从lodash官方网站直接获得的文档确实对此进行了说明,但是您会被误解原谅,因为如果您不熟悉它们的术语,那么您会理解很多内容:


Throttle Documentation *See the Throttle Documentation on Lodash


这是什么意思?

在您的示例中,当您调用_.throttle时,它将默认情况下,等待执行该函数调用,直到间隔过去,并在执行过程中连续重写等待调用的函数。 100ms个间隔。要更改此设置并仅接受/执行间隔后进行的呼叫,可以将trailing更改为false

可行的解决方案:

function say(what) {
console.group();
  console.log(what);
  console.timeLog("check");
  console.groupEnd();
}

const t = _.throttle(say, 100, {trailing: false});
const TO = (n, i) => setTimeout(()=>{t(n);}, i);
 
console.time("check");
TO(1,50);
TO(1,50);
TO(1,50);
TO(1,55);
TO(2,55);
TO(3,500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>