正确理解 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

  1. 但是为什么 “console.log('no hurry please');”永远不会被调用?

当我调用 runOnce(x);runOnce(x);runOnce(y);runOnce(y); 时, 函数 x 函数 y 只被调用 1 次,这很好。

  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() 可以跳过它。