【问题标题】:How to properly debounce ajax requests如何正确地去抖动 ajax 请求
【发布时间】:2014-05-06 11:41:16
【问题描述】:

我有一个可以切换某些行为的复选框,但是如果有人连续点击 100 次,我不想向我的服务器端发送 100 个请求。

这是我到目前为止所得到的(找到这个代码 sn-p):

deBouncer = function($,cf,of, interval){
    var debounce = function (func, threshold, execAsap) {
        var timeout;
        return function debounced () {
          var obj = this, args = arguments;
          function delayed () {
            if (!execAsap)
                func.apply(obj, args);
            timeout = null;
          }
          if (timeout)
            clearTimeout(timeout);  
          else if (execAsap)
            func.apply(obj, args);
          timeout = setTimeout(delayed, threshold || interval);
        }
    }
    jQuery.fn[cf] = function(fn){  return fn ? this.bind(of, debounce(fn)) : this.trigger(cf); };
  };

在我的文档准备功能中:

deBouncer(jQuery,'smartoggle', 'click', 1500);

然后是事件本身:

$(window).smartoggle(function(e){
  MyToggleFunction();
});

这是因为我将 1500 毫秒作为去抖动周期,因此如果您在 1500 毫秒内单击 n 次,它只会将最新状态发送到服务器。

但是使用这个有副作用,现在我的其他东西的点击事件搞砸了。我在这里做错了吗?有没有更好的去抖动方法?

【问题讨论】:

  • 您肯定在此处的写入轨道上。不过,我只会将此事件绑定到有问题的复选标记。这可能会让你简化一些其他的编码。
  • @JeremyJStarcher 你能举例说明你的意思吗?
  • 我需要看看你的标记......或者我可以根据我的做法给你一个虚构的例子。

标签: javascript jquery ajax


【解决方案1】:

我认为这个问题比最初看起来要好。 Http Ajax 请求的工作方式有一个警告。如果您将延迟设置为 1500 毫秒,并且您可以保证每个请求都在此时间范围内得到服务,那么其他答案就可以正常工作。但是,如果任何请求变得非常缓慢,那么请求可能会出现故障。如果发生这种情况,最后处理的请求就是显示数据的请求,而不是最后发送的请求。

我编写了这个类来避免这个警告(在 Typescript 中,但你应该能够阅读它):

export class AjaxSync {

  private isLoading: boolean = false;
  private pendingCallback: Function;
  private timeout;

  public debounce(time: number, callback: Function): Function {
    return this.wrapInTimeout(
      time,
      () => {
        if (this.isLoading) {
          this.pendingCallback = callback;
          return;
        }
        this.isLoading = true;
        callback()
          .then(() => {
            this.isLoading = false;
            if (this.pendingCallback) {
              const pendingCallback = this.pendingCallback;
              this.pendingCallback = null;
              this.debounce(time, pendingCallback);
            }
          });
      }
    );
  }

  private wrapInTimeout(time, callback) {
    return () => {
      clearTimeout(this.timeout);
      this.timeout = setTimeout(callback, time);
    };
  }
}

这将防止同时处理两个 ajax 请求,如果有一个未决的请求,这将发送另一个请求。

【讨论】:

    【解决方案2】:

    不确定是否有“正确”的方法来做到这一点。

    话虽如此,underscore 有这样一个实用程序,可以创建函数的去抖动版本......

    var MyToggleDebounced = _.debounce(MyToggleFunction, 1500);
    

    然后在您的点击处理程序中使用MyToggleDebounced

    Link to debounce docs on underscorejs

    查看带注释的来源,了解他们是如何做到的。

    【讨论】:

      【解决方案3】:

      只需对执行实际工作的函数进行去抖动处理,我不会为此加载整个库。

      var debouncedSomeFunction = debounce(someFunction, 1500);
      
      debouncedSomeFunction();
      debouncedSomeFunction();
      debouncedSomeFunction();
      
      setTimeout(debouncedSomeFunction, 2000);
      
      
      function debounce(fn, bufferInterval) {
        var timeout;
      
        return function () {
          clearTimeout(timeout);
          timeout = setTimeout(fn.apply.bind(fn, this, arguments), bufferInterval);
        };
      
      }
      
      function someFunction() {
          log('someFunction executed');
      }
      
      function log(text) {
         document.body.appendChild(document.createTextNode(text));
         document.body.appendChild(document.createElement('br'));
      }

      【讨论】:

      • 我知道这是伪代码,但我真的很困惑最后一行的自引用含义。也许您可以更新您的答案以显示 yourFunction 的简单实现?我尝试了这段代码,但无法正常工作。
      • 为了清楚起见,以防其他人被最后一行弄糊涂了...应该是 *var yourFunction = function(){}; yourFunction = debounce(yourFunction, 1500);
      • @geoidesic 我修改了代码,希望这样更容易理解。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-26
      • 2020-07-22
      • 1970-01-01
      • 1970-01-01
      • 2016-07-31
      • 2020-08-11
      • 1970-01-01
      相关资源
      最近更新 更多