繁体   English   中英

如何正确 debounce ajax 请求

[英]How to properly debounce ajax requests

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

这是我到目前为止所得到的(找到了这个代码片段):

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 次,它将仅将最新状态发送到服务器。

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

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

 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')); }

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

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

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

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

链接到 underscorejs 上的 debounce 文档

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

我认为这个问题比最初看起来要好。 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 请求,如果有一个待处理的请求,这将发送另一个请求。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM