I am looking for a simple throttle in JavaScript. I know libraries like lodash and underscore have it, but only for one function it will be overkill to include any of those libraries.

I was also checking if jQuery has a similar function - could not find.

I have found one working throttle,下面是代码:

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.

推荐答案

I would use the underscore.js or lodash source code to find a well tested version of this function.

下面是下划线代码的稍微修改版本,用于删除对下划线的所有引用.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.

请在下面找到此功能的一个非常简单且不可配置的版本:

function throttle (callback, limit) {
    var waiting = false;                      // Initially, we're not waiting
    return function () {                      // We return a throttled function
        if (!waiting) {                       // If we're not waiting
            callback.apply(this, arguments);  // Execute users function
            waiting = true;                   // Prevent future invocations
            setTimeout(function () {          // After a period of time
                waiting = false;              // And allow future invocations
            }, limit);
        }
    }
}

编辑1:删除了对@zettam comments 的另一个下划线引用,thx

编辑2:在@lolzery@wowzery的 comments 中添加了关于lodash和可能的代码简化的建议

编辑3:由于受欢迎的请求,我添加了一个非常简单、不可配置的函数版本,根据@vsync的 comments 改编

Jquery相关问答推荐

在shiny 的datatable列中启用智能搜索

将搜索面板和服务器端与POST AJAX请求一起使用时出现DataTables错误

哪个 JQuery Select 器会排除与给定 Select 器匹配的父项的项目?

在 textarea 输入中美化 json 数据

在 jQuery 中构建 html 元素的最清晰方法

使用 jQuery 为 box-shadow 设置动画的正确方法

在 `click` 和 `enter` 上触发事件

jQuery JSON到字符串?

jQuery绑定到粘贴事件,如何获取粘贴的内容

删除所有子元素的 CLASS

jQuery计算所有文本字段中的值的总和

按值对 Html Select 的选项进行排序的最有效方法是什么,同时保留当前选定的项目?

如何在实际图像下载时显示加载图像

如何使所有浏览器都支持 ?有什么 Select 吗?

删除索引后的所有项目

使用 JavaScript 获取用户代理

jQuery、复选框和 .is(":checked")

如何在 TypeScript 中获得 jQuery 自动完成功能?

JQuery - 按值查找单选按钮

jQuery 使用 AND 和 OR 运算符按属性 Select