Javascript js中的简单油门
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27078285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Simple throttle in js
提问by Mia
I am looking for a simple throttle in JS. I know libraries like lodash and underscore have it, but only for one function it will be overkill to include any of those libraries.
我正在寻找一个简单的 JS 节流阀。我知道像 lodash 和 underscore 这样的库有它,但仅对于一个函数来说,包含这些库中的任何一个都太过分了。
I was also checking if jquery has a similar function - could not find.
我也在检查 jquery 是否有类似的功能 - 找不到。
I have found one working throttle, and here is the code:
我找到了一个工作油门,这是代码:
function throttle(fn, threshhold, scope) {
threshhold || (threshhold = 250);
var last,
deferTimer;
return function () {
var context = scope || this;
var now = +new Date,
args = arguments;
if (last && now < last + threshhold) {
// hold on to it
clearTimeout(deferTimer);
deferTimer = setTimeout(function () {
last = now;
fn.apply(context, args);
}, threshhold);
} else {
last = now;
fn.apply(context, args);
}
};
}
The problem with this is: it fires the function once more after the throttle time is complete. So let's assume I made a throttle that fires every 10 seconds on keypress - if I do keypress 2 times, it will still fire the second keypress when 10 seconds are completed. I do not want this behavior.
问题在于:它在油门时间完成后再次触发该功能。所以让我们假设我做了一个每 10 秒在按键时触发的油门 - 如果我按键 2 次,它仍然会在 10 秒完成后触发第二个按键。我不想要这种行为。
回答by Clément Prévost
I would use the underscore.jsor lodashsource code to find a well tested version of this function.
我会使用underscore.js或lodash源代码来找到这个函数的经过良好测试的版本。
Here is the slightly modified version of the underscore code to remove all references to underscore.js himself:
这是下划线代码的略微修改版本,用于删除对 underscore.js 本身的所有引用:
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. Normally, the throttled function will run
// as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto.
function throttle(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : Date.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function() {
var now = Date.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};
Please note that this code can be simplified if you don't need all the options that underscore support.
请注意,如果您不需要所有强调支持的选项,则可以简化此代码。
Edit 1: Removed another reference to underscore, thx to Zettam's comment
编辑 1:删除了对下划线的另一个引用,感谢 Zettam 的评论
Edit 2: Added suggestion about lodash and possible code simplification, thx to lolzery wowzery's comment
编辑 2:添加了关于 lodash 和可能的代码简化的建议,感谢 lolzery wowzery 的评论
回答by Vikas Bansal
callback: takes the function that should be called
callback: 接受应该被调用的函数
limit: number of times that function should be called within the time limit
limit: 在时间限制内应调用该函数的次数
time: time span to reset the limit count
time: 重置限制计数的时间跨度
functionality and usage: Suppose you have an API that allows user to call it 10 times in 1 minute
功能和用法:假设您有一个允许用户在 1 分钟内调用 10 次的 API
function throttling(callback, limit, time) {
/// monitor the count
var calledCount = 0;
/// refresh the `calledCount` varialbe after the `time` has been passed
setInterval(function(){ calledCount = 0 }, time);
/// creating a closure that will be called
return function(){
/// checking the limit (if limit is exceeded then do not call the passed function
if (limit > calledCount) {
/// increase the count
calledCount++;
callback(); /// call the function
}
else console.log('not calling because the limit has exceeded');
};
}
////////////////////////////////////////////////////////////
// how to use
/// creating a function to pass in the throttling function
function cb(){
console.log("called");
}
/// calling the closure function in every 100 milliseconds
setInterval(throttling(cb, 3, 1000), 100);
回答by Divyanshu Maithani
Adding to the discussion here (and for more recent visitors), if the reason for not using the almost de facto throttlefrom lodashis to have a smaller sized package or bundle, then it's possible to include only throttlein your bundle instead of the entire lodashlibrary. For example in ES6, it would be something like:
添加到此处的讨论中(以及对于最近的访问者),如果不使用几乎事实上的throttlefrom 的原因lodash是具有较小尺寸的包或包,则可以仅包含throttle在您的包中而不是整个lodash库中。例如在 ES6 中,它会是这样的:
import throttle from 'lodash/throttle';
Also, there is a throttleonly package from lodashcalled lodash.throttlewhich can be used with a simple importin ES6 or requirein ES5.
此外,throttle只有一个来自lodashcalled 的包lodash.throttle可以与importES6 或requireES5 中的 simple 一起使用。
回答by smartmouse
回答by vipin goyal
Here's how I implemented throttle function in ES6 in 9LOC, hope it helps
下面是我在 9LOC 的 ES6 中实现油门功能的方法,希望对你有帮助
function throttle(func, delay) {
let timeout = null
return function(...args) {
if (!timeout) {
timeout = setTimeout(() => {
func.call(this, ...args)
timeout = null
}, delay)
}
}
}
Click on this linkto see how it works.
单击此链接以查看它是如何工作的。
回答by akinuri
I've just needed a throttle/debounce function for window resize event, and being curious, I also wanted to know what these are and how they work.
我只需要一个用于调整窗口大小事件的节流/去抖动功能,出于好奇,我还想知道这些是什么以及它们是如何工作的。
I've read multiple blog posts and QAs on SO, but they all seem to overcomplicate this, suggest libraries, or just provide descriptions and not simple plain JS implementations.
我已经阅读了多篇关于 SO 的博客文章和 QA,但它们似乎都过于复杂,建议使用库,或者只提供描述而不是简单的普通 JS 实现。
I won't provide a description since it's plentiful. So here's my implementation:
我不会提供描述,因为它很丰富。所以这是我的实现:
function throttle(callback, delay) {
var timeoutHandler = null;
return function () {
if (timeoutHandler == null) {
timeoutHandler = setTimeout(function () {
callback();
clearInterval(timeoutHandler);
timeoutHandler = null;
}, delay);
}
}
}
function debounce(callback, delay) {
var timeoutHandler = null;
return function () {
clearTimeout(timeoutHandler);
timeoutHandler = setTimeout(function () {
callback();
}, delay);
}
}
These might need tweaks (e.g., initially the callback isn't called immediately).
这些可能需要调整(例如,最初不会立即调用回调)。
See the difference in action (try resizing the window):
查看操作的差异(尝试调整窗口大小):
function throttle(callback, delay) {
var timeoutHandler = null;
return function () {
if (timeoutHandler == null) {
timeoutHandler = setTimeout(function () {
callback();
clearInterval(timeoutHandler);
timeoutHandler = null;
}, delay);
}
}
}
function debounce(callback, delay) {
var timeoutHandler = null;
return function () {
clearTimeout(timeoutHandler);
timeoutHandler = setTimeout(function () {
callback();
}, delay);
}
}
var cellDefault = document.querySelector("#cellDefault div");
var cellThrottle = document.querySelector("#cellThrottle div");
var cellDebounce = document.querySelector("#cellDebounce div");
window.addEventListener("resize", function () {
var span = document.createElement("span");
span.innerText = window.innerWidth;
cellDefault.appendChild(span);
cellDefault.scrollTop = cellDefault.scrollHeight;
});
window.addEventListener("resize", throttle(function () {
var span = document.createElement("span");
span.innerText = window.innerWidth;
cellThrottle.appendChild(span);
cellThrottle.scrollTop = cellThrottle.scrollHeight;
}, 500));
window.addEventListener("resize", debounce(function () {
var span = document.createElement("span");
span.innerText = window.innerWidth;
cellDebounce.appendChild(span);
cellDebounce.scrollTop = cellDebounce.scrollHeight;
}, 500));
table {
border-collapse: collapse;
margin: 10px;
}
table td {
border: 1px solid silver;
padding: 5px;
}
table tr:last-child td div {
width: 60px;
height: 200px;
overflow: auto;
}
table tr:last-child td span {
display: block;
}
<table>
<tr>
<td>default</td>
<td>throttle</td>
<td>debounce</td>
</tr>
<tr>
<td id="cellDefault">
<div></div>
</td>
<td id="cellThrottle">
<div></div>
</td>
<td id="cellDebounce">
<div></div>
</td>
</tr>
</table>
回答by makore
Here's my own version of Vikaspost:
这是我自己的Vikas帖子版本:
throttle: function (callback, limit, time) {
var calledCount = 0;
var timeout = null;
return function () {
if (limit > calledCount) {
calledCount++;
callback();
}
if (!timeout) {
timeout = setTimeout(function () {
calledCount = 0
timeout = null;
}, time);
}
};
}
I find that using setIntervalis not a good idea.
我发现使用setInterval不是一个好主意。
回答by Roman
This throttle function is build on ES6. Callback functions takes arguments (args), and still it works wrapped with throttle function. Be free to customize delay time according to your app needs. 1 time per 100ms is used for development mode, event "oninput" is just an example for frequent case of its use:
这个油门功能建立在 ES6 之上。回调函数接受参数(args),它仍然可以与油门函数一起工作。可根据您的应用需求自由自定义延迟时间。每 100ms 1 次用于开发模式,事件“oninput”只是频繁使用的一个例子:
const callback = (...args) => {
console.count('callback throttled with arguments:', args);
};
throttle = (callback, limit) => {
let timeoutHandler = 'null'
return (...args) => {
if (timeoutHandler === 'null') {
timeoutHandler = setTimeout(() => {
callback(...args)
timeoutHandler = 'null'
}, limit)
}
}
}
window.addEventListener('oninput', throttle(callback, 100));
P.S. As @Anshul explained: throttling enforces a maximum number of times a function can be called over time. As in "execute this function at most once every 100 milliseconds."
PS 正如@Anshul 解释的那样:节流会强制执行一个函数随着时间的推移可以调用的最大次数。如“最多每 100 毫秒执行一次此函数”。
回答by Almenon
I made a npm package with some throttling functions:
我制作了一个带有一些节流功能的 npm 包:
npm install function-throttler
npm 安装功能节流器
throttleAndQueue
油门和队列
Returns a version of your function that can be called at most every W milliseconds, where W is wait. Calls to your func that happen more often than W get queued up to be called every W ms
返回最多每 W 毫秒调用一次的函数版本,其中 W 是等待。对您的 func 的调用比 W 更频繁地排队等待每 W ms 调用一次
throttledUpdate
节流更新
Returns a version of your function that can be called at most every W milliseconds, where W is wait. for calls that happen more often than W the last call will be the one called (last takes precedence)
返回最多每 W 毫秒调用一次的函数版本,其中 W 是等待。对于比 W 更频繁发生的调用,最后一个调用将是被调用的调用(最后一个优先)
throttle
风门
limits your function to be called at most every W milliseconds, where W is wait. Calls over W get dropped
限制您的函数最多每 W 毫秒调用一次,其中 W 是等待。W 上的电话掉线
回答by Rainb
There is a library suited for this purpose, it's Backburner.js from Ember.
有一个适合此目的的库,它是 Ember 的 Backburner.js。
https://github.com/BackburnerJS/
https://github.com/BackburnerJS/
You'd use it so.
你会这样用的。
var backburner = new Backburner(["task"]); //You need a name for your tasks
function saySomething(words) {
backburner.throttle("task", console.log.bind(console, words)
}, 1000);
}
function mainTask() {
"This will be said with a throttle of 1 second per word!".split(' ').map(saySomething);
}
backburner.run(mainTask)

