Mia*_*Mia 56 javascript jquery
我在JS寻找一个简单的油门.我知道像lodash和下划线这样的库有它,但只有一个函数包含任何这些库都是过度的.
我还在检查jquery是否有类似的功能 - 找不到.
我找到了一个工作油门,这是代码:
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);
}
};
}
Run Code Online (Sandbox Code Playgroud)
这个问题是:它在节流时间结束后再次激活该功能.所以我们假设我在按键时每隔10秒发一个油门 - 如果我按下2次按键,它会在10秒钟完成时触发第二次按键.我不想要这种行为.
Clé*_*ost 64
我会使用underscore.js或lodash源代码来查找此函数的经过良好测试的版本.
下面是下划线代码的略微修改版本,用于删除对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;
};
};
Run Code Online (Sandbox Code Playgroud)
请注意,如果您不需要所有支持下划线的选项,则可以简化此代码.
编辑1:删除了对下划线的另一个引用,thx到Zettam的评论
编辑2:添加了关于lodash和可能的代码简化的建议,thx to lolzery wowzery的评论
sma*_*use 20
那这个呢?
function throttle(func, timeFrame) {
var lastTime = 0;
return function () {
var now = new Date();
if (now - lastTime >= timeFrame) {
func();
lastTime = now;
}
};
}
Run Code Online (Sandbox Code Playgroud)
简单的。
您可能有兴趣查看源代码。
Vik*_*sal 12
callback:接受应该调用的函数
limit:应在时间限制内调用该函数的次数
time:重置限制计数的时间跨度
功能和用法:假设您有一个API,允许用户在1分钟内调用它10次
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);Run Code Online (Sandbox Code Playgroud)
小智 10
这是一个与vsync的解决方案相同的限制函数,添加了将参数传递给限制函数.
function throttle (callback, limit) {
var wait = false;
return function () {
if (!wait) {
callback.apply(null, arguments);
wait = true;
setTimeout(function () {
wait = false;
}, limit);
}
}
}
Run Code Online (Sandbox Code Playgroud)
可以像这样使用:
window.addEventListener('resize', throttle(function(e){console.log(e)}, 100));
Run Code Online (Sandbox Code Playgroud)
在没有addEventListener上下文的情况下使用:
throttle(function(arg1, arg2){console.log(arg1, arg2);}, 100)('red', 'blue');
// red blue
Run Code Online (Sandbox Code Playgroud)
下面是我在 9LOC 的 ES6 中实现油门功能的方法,希望对你有帮助
function throttle(func, delay) {
let timeout = null
return function(...args) {
if (!timeout) {
timeout = setTimeout(() => {
func.call(this, ...args)
timeout = null
}, delay)
}
}
}
Run Code Online (Sandbox Code Playgroud)
单击此链接以查看它是如何工作的。
添加到这里的讨论(以及更近的游客),如果不使用的原因,几乎实际上throttle从lodash是有一个小尺寸的包或捆绑,则有可能只包括throttle在你的包,而不是整个lodash库。例如在ES6中,它将类似于:
import throttle from 'lodash/throttle';
Run Code Online (Sandbox Code Playgroud)
此外,还有一个throttle只能从封装lodash称为lodash.throttle其可以用简单的使用import在ES6或require在ES5。
我只需要一个用于调整窗口大小事件的节流/去抖动功能,出于好奇,我还想知道这些是什么以及它们是如何工作的。
我已经阅读了多篇关于 SO 的博客文章和 QA,但它们似乎都过于复杂,建议使用库,或者只提供描述而不是简单的普通 JS 实现。
我不会提供描述,因为它很丰富。所以这是我的实现:
function throttle(callback, delay) {
var timeoutHandler = null;
return function () {
if (timeoutHandler == null) {
timeoutHandler = setTimeout(function () {
callback();
timeoutHandler = null;
}, delay);
}
}
}
function debounce(callback, delay) {
var timeoutHandler = null;
return function () {
clearTimeout(timeoutHandler);
timeoutHandler = setTimeout(function () {
callback();
}, delay);
}
}
Run Code Online (Sandbox Code Playgroud)
这些可能需要调整(例如,最初不会立即调用回调)。
查看操作的差异(尝试调整窗口大小):
function throttle(callback, delay) {
var timeoutHandler = null;
return function () {
if (timeoutHandler == null) {
timeoutHandler = setTimeout(function () {
callback();
timeoutHandler = null;
}, delay);
}
}
}
function debounce(callback, delay) {
var timeoutHandler = null;
return function () {
clearTimeout(timeoutHandler);
timeoutHandler = setTimeout(function () {
callback();
}, delay);
}
}
Run Code Online (Sandbox Code Playgroud)
function throttle(callback, delay) {
var timeoutHandler = null;
return function () {
if (timeoutHandler == null) {
timeoutHandler = setTimeout(function () {
callback();
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));Run Code Online (Sandbox Code Playgroud)
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;
}Run Code Online (Sandbox Code Playgroud)
我在这里看到了很多答案,对于“js 中的简单节流”来说太复杂了。
几乎所有更简单的答案都只是忽略“节流”中的调用,而不是将执行延迟到下一个间隔。
这是一个简单的实现,也可以处理“节流中”的调用:
const throttle = (func, limit) => {
let lastFunc;
let lastRan = Date.now() - (limit + 1); //enforces a negative value on first run
return function(...args) {
const context = this;
clearTimeout(lastFunc);
lastFunc = setTimeout(() => {
func.apply(context, args);
lastRan = Date.now();
}, limit - (Date.now() - lastRan)); //negative values execute immediately
}
}
Run Code Online (Sandbox Code Playgroud)
这与简单去抖动的实现几乎完全相同。它只是添加了超时延迟的计算,需要跟踪函数上次运行的时间。见下文:
const debounce = (func, limit) => {
let lastFunc;
return function(...args) {
const context = this;
clearTimeout(lastFunc);
lastFunc = setTimeout(() => {
func.apply(context, args)
}, limit); //no calc here, just use limit
}
}
Run Code Online (Sandbox Code Playgroud)