正确理解 javascript 中的油门
Understanding throttle in javascript the correct way
嗨,我正在尝试了解 javascript 中的限制。
我有这个代码
function runOnce(fn, ms) {
if(typeOf(fn) !== "function")
return;
ms = ms || 5000;
var active;
return (function() {
if(active) {
console.log('no hurry please');
} else {
active = setTimeout(fn, ms);
}
})();
};
我想使用两个不同的回调函数进行测试
function x() {
console.log('timeout from x');
}
function y() {
console.log('timeout from y');
}
下面是我的问题:
多次调用runOnce(x);runOnce(x);runOnce(x);
,throttle函数似乎没问题(只调用了一次function x)
- 但是为什么
“console.log('no hurry please');”永远不会被调用?
当我调用 runOnce(x);runOnce(x);runOnce(y);runOnce(y);
时, 函数 x 和 函数 y 只被调用 1 次,这很好。
- 但是为什么如果我调用
runOnce(x);runOnce(y);runOnce(x);runOnce(y);
,函数 x 和 函数 y 都被调用了 2 次?
谢谢
问题出在我的 runOnce 代码中。
如果我将 var active 移到函数之外就解决了(感谢@Andreas 的 link)。并稍微修复一下功能。以下完整代码工作:
var active, fnArray = [];
function runOnce(fn, ms) {
if (typeof(fn) !== "function")
return;
ms = ms || 5000;
return (function() {
if (active && fnArray.indexOf(fn.name) >= 0) {
console.log('no hurry please');
} else {
fnArray.push(fn.name);
active = setTimeout(function() {
fnArray = fnArray.filter(function(elm) {
elm !== fn.name
});
fn();
}, ms);
}
})();
};
function x() {
document.body.innerHTML += 'timeout from x </br>';
}
function y() {
document.body.innerHTML += 'timeout from y </br>';
}
runOnce(x);
runOnce(x);
runOnce(x);
runOnce(y);
runOnce(x);
runOnce(y);
如何限制特定时间范围内的调用次数(例如调用 XYZ()):
var throttleCallsObj = new Object({ maxCallsPerFrame: 10, mSecFrame: 2000 });
function isCallBlocked(key)
{
var nowDateTime = Date.now();
if (typeof throttleCallsObj[key] === 'undefined')
throttleCallsObj[key] = new Object;
else
{
if (throttleCallsObj[key].dt > nowDateTime)
return throttleCallsObj[key].nCalls >= throttleCallsObj.maxCallsPerFrame;
}
throttleCallsObj[key].dt = nowDateTime + throttleCallsObj.mSecFrame;
throttleCallsObj[key].nCalls = 0;
return false;
}
function countUnblockedCalls(key)
{
if (typeof throttleCallsObj[key] === 'undefined')
return;
throttleCallsObj[key].nCalls += 1;
return throttleCallsObj[key].nCalls == throttleCallsObj.maxCallsPerFrame;
}
用法:
function showMessage_A()
{
if (isCallBlocked("typeA", 5, 200))
return;
/* your code ... */
countUnblockedCalls("typeA", 200);
XYZ();
}
function showMessage_B()
{
if (isCallBlocked("typeB"))
return;
/* your code ... */
countUnblockedCalls("typeB");
XYZ();
}
countUnblockedCalls
作为一个单独的函数,因为如果您的代码不调用 XYZ() 可以跳过它。
嗨,我正在尝试了解 javascript 中的限制。 我有这个代码
function runOnce(fn, ms) {
if(typeOf(fn) !== "function")
return;
ms = ms || 5000;
var active;
return (function() {
if(active) {
console.log('no hurry please');
} else {
active = setTimeout(fn, ms);
}
})();
};
我想使用两个不同的回调函数进行测试
function x() {
console.log('timeout from x');
}
function y() {
console.log('timeout from y');
}
下面是我的问题:
多次调用runOnce(x);runOnce(x);runOnce(x);
,throttle函数似乎没问题(只调用了一次function x)
- 但是为什么 “console.log('no hurry please');”永远不会被调用?
当我调用 runOnce(x);runOnce(x);runOnce(y);runOnce(y);
时, 函数 x 和 函数 y 只被调用 1 次,这很好。
- 但是为什么如果我调用
runOnce(x);runOnce(y);runOnce(x);runOnce(y);
,函数 x 和 函数 y 都被调用了 2 次?
谢谢
问题出在我的 runOnce 代码中。 如果我将 var active 移到函数之外就解决了(感谢@Andreas 的 link)。并稍微修复一下功能。以下完整代码工作:
var active, fnArray = [];
function runOnce(fn, ms) {
if (typeof(fn) !== "function")
return;
ms = ms || 5000;
return (function() {
if (active && fnArray.indexOf(fn.name) >= 0) {
console.log('no hurry please');
} else {
fnArray.push(fn.name);
active = setTimeout(function() {
fnArray = fnArray.filter(function(elm) {
elm !== fn.name
});
fn();
}, ms);
}
})();
};
function x() {
document.body.innerHTML += 'timeout from x </br>';
}
function y() {
document.body.innerHTML += 'timeout from y </br>';
}
runOnce(x);
runOnce(x);
runOnce(x);
runOnce(y);
runOnce(x);
runOnce(y);
如何限制特定时间范围内的调用次数(例如调用 XYZ()):
var throttleCallsObj = new Object({ maxCallsPerFrame: 10, mSecFrame: 2000 });
function isCallBlocked(key)
{
var nowDateTime = Date.now();
if (typeof throttleCallsObj[key] === 'undefined')
throttleCallsObj[key] = new Object;
else
{
if (throttleCallsObj[key].dt > nowDateTime)
return throttleCallsObj[key].nCalls >= throttleCallsObj.maxCallsPerFrame;
}
throttleCallsObj[key].dt = nowDateTime + throttleCallsObj.mSecFrame;
throttleCallsObj[key].nCalls = 0;
return false;
}
function countUnblockedCalls(key)
{
if (typeof throttleCallsObj[key] === 'undefined')
return;
throttleCallsObj[key].nCalls += 1;
return throttleCallsObj[key].nCalls == throttleCallsObj.maxCallsPerFrame;
}
用法:
function showMessage_A()
{
if (isCallBlocked("typeA", 5, 200))
return;
/* your code ... */
countUnblockedCalls("typeA", 200);
XYZ();
}
function showMessage_B()
{
if (isCallBlocked("typeB"))
return;
/* your code ... */
countUnblockedCalls("typeB");
XYZ();
}
countUnblockedCalls
作为一个单独的函数,因为如果您的代码不调用 XYZ() 可以跳过它。