jQuery 中的限制事件调用

IT技术 javascript jquery events
2021-01-27 18:24:17

我有一个keyup事件绑定到一个需要大约四分之一秒才能完成的函数。

$("#search").keyup(function() {
  //code that takes a little bit to complete
});

当用户输入一个完整的单词或快速按键时,该功能将被连续调用多次,并且需要一段时间才能完成。

有没有办法限制事件调用,以便如果有几个快速连续调用,它只触发最近调用的那个?

6个回答

看看jQuery Debounce

$('#search').keyup($.debounce(function() {
    // Will only execute 300ms after the last keypress.
}, 300));
当我使用多个选择器时,这不起作用 .sel1, .sel2 sel3
2021-03-22 18:24:17
@HungryCoder:它确实有效。 当然,每个匹配的元素都将共享相同的计时器,因此在您完全停止发送事件后才会触发回调。
2021-03-24 18:24:17
这并没有回答这个问题。OP 可能认为它已经得到了回答,但这甚至不是所描述的内容的一半,并且绝不接近自动完成结果的预期行为。去抖是错误的功能。OP实际上是在要求油门。请参阅:css-tricks.com/the-difference-between-throttling-and-debouncing
2021-03-27 18:24:17
Debounce 不是节流..它是别的东西
2021-04-08 18:24:17
@vsync:挑剔的术语。OP 说的是“油门”,但真正的意思是“去抖”
2021-04-12 18:24:17

这是一个不需要插件的潜在解决方案。使用布尔值来决定是执行 keyup 回调,还是跳过它。

var doingKeyup = false;

$('input').keyup(function(){
    if(!doingKeyup){
        doingKeyup=true;
        // slow process happens here
        doingKeyup=false;
    }
});
@josh3736 公平地说,问题标题确实要求“节流”。不过,我之前没有听说过“去抖动”。
2021-03-21 18:24:17
我不会对他的搜索领域的工作方式进行假设。
2021-03-25 18:24:17
只有// slow process在另一个事件循环中发生时,这才是正确的方式,否则因为 JS 是单线程的,这没有用。
2021-03-25 18:24:17
这种方法还有一个问题——如果在前一个处理程序运行时输入了最后一个字符或一系列字符,它不会在最终文本字符串上触发。
2021-03-28 18:24:17
这是节流阀,而不是去抖动。对于搜索字段,您希望在用户完成输入(去抖动)运行搜索,而不是在他们输入一个字符(节流阀)运行搜索Debounce 插件实际上只是一个 <1 kB 的便捷方法,它封装了对setTimeout/ 的调用clearTimeout
2021-04-10 18:24:17

你也可以使用优秀的Underscore/_库。

Josh 的回答中的评论,目前最流行的,争论是否真的应该限制通话,或者是否需要去抖动器。区别有点微妙,但 Underscore 同时具有:_.debounce(function, wait, [immediate])_.throttle(function, wait, [options]).

如果您还没有使用 Underscore,请检查一下。它可以让你的 JavaScript 更简洁,并且足够轻量级让大多数库讨厌者停下来。

这是使用 JQuery 执行此操作的一种简洁方法。

    /* delayed onchange while typing jquery for text boxes widget
    usage:
        $("#SearchCriteria").delayedChange(function () {
            DoMyAjaxSearch();
        });

    */
    (function ($) {
        $.fn.delayedChange = function (options) {
            var timer;
            var o;

            if (jQuery.isFunction(options)) {
                o = { onChange: options };
            }
            else
                o = options;

            o = $.extend({}, $.fn.delayedChange.defaultOptions, o);

            return this.each(function () {
                var element = $(this);
                element.keyup(function () {
                    clearTimeout(timer);
                    timer = setTimeout(function () {
                        var newVal = element.val();
                        newVal = $.trim(newVal);
                        if (element.delayedChange.oldVal != newVal) {
                            element.delayedChange.oldVal = newVal;
                            o.onChange.call(this);
                        }

                    }, o.delay);
                });
            });


        };

        $.fn.delayedChange.defaultOptions = {
            delay: 1000,
            onChange: function () { }
        }

        $.fn.delayedChange.oldVal = "";


    })(jQuery);

节流方法的两个小型通用实现。(我更喜欢通过这些简单的函数来完成,而不是添加另一个 jquery 插件)

  1. 上次通话后等待一段时间

    当我们不想在用户不断输入查询时调用例如搜索功能时,这个很有用

function throttle(time, func) {
  if (!time || typeof time !== "number" || time < 0) {
      return func;
  }

  var throttleTimer = 0;

  return function() {
    var args = arguments;
    clearTimeout(throttleTimer);
    throttleTimer = setTimeout(function() {
      func.apply(null, args);
    }, time);
  }
}
  1. 调用给定函数的频率不超过给定的时间

    下面一个对刷新日志很有用

function throttleInterval(time, func) {
  if (!time || typeof time !== "number" || time < 0) {
      return func;
  }

  var throttleTimer = null;
  var lastState = null;
  var eventCounter = 0;
  var args = [];

  return function() {
    args = arguments;
    eventCounter++;
    if (!throttleTimer) {
      throttleTimer = setInterval(function() {
        if (eventCounter == lastState) {
          clearInterval(throttleTimer);
          throttleTimer = null;
          return;
        }

        lastState = eventCounter;
        func.apply(null, args);
      }, time);
    }
  }
}

用法很简单:

以下是在 inputBox 中最后一次击键后等待 2 秒,然后调用应该被限制的函数。

$("#inputBox").on("input", throttle(2000, function(evt) {
  myFunctionToThrottle(evt);
}));

这是您可以同时测试的示例:单击 (CodePen)

这两个示例都是去抖动方法,而不是油门 ;)
2021-04-07 18:24:17