【问题标题】:How to cancel a debounced function after it is called and before it executes?如何在调用后和执行前取消去抖动函数?
【发布时间】:2015-03-12 14:48:14
【问题描述】:

我创建了一个带下划线的函数的去抖动版本:

var debouncedThing = _.debounce(thing, 1000);

一旦 debouncedThing 被调用...

debouncedThing();

...在实际执行之前的等待期间,有什么办法可以取消它?

【问题讨论】:

  • 这个问题不清楚。我的是具体的。这个问题没有回答我的问题。
  • 当然你可以实现你自己版本的去抖动器,它会以某种方式暴露timeout或清除超时的函数。
  • 这个回答很好我希望你删除了downvote

标签: javascript underscore.js


【解决方案1】:

如果您使用 lodash 的最新版本,您可以简单地这样做:

// create debounce
const debouncedThing = _.debounce(thing, 1000);

// execute debounce, it will wait one second before executing thing
debouncedThing();

// will cancel the execution of thing if executed before 1 second
debouncedThing.cancel()

另一种解决方案是使用标志:

// create the flag
let executeThing = true;

const thing = () => {
   // use flag to allow execution cancelling
   if (!executeThing) return false;
   ...
};

// create debounce
const debouncedThing = _.debounce(thing, 1000);

// execute debounce, it will wait one second before executing thing
debouncedThing();

// it will prevent to execute thing content
executeThing = false;

【讨论】:

    【解决方案2】:

    旧的,但为到达这里的其他人添加注释。

    文档(我现在正在查看 1.9.1)说您应该能够做到:

    var fn = () => { console.log('run'); };
    var db = _.debounce(fn, 1000);
    db();
    db.cancel();
    

    这将做 OP 想做的事情(以及我想做的事情)。它不会打印控制台消息。

    我从来没有让这个工作。正如 Underscore 文档中所承诺的那样,我对 .cancel() 进行了高低查找,但我找不到它。

    如果您使用的是下划线,请使用 Carlos Ruana 接受的答案中的标志选项。遗憾的是(在我看来)我的要求不允许从 Underscore 升级到 Lodash(在我看来)。下划线的功能较少,但比没有下划线的功能更多。

    【讨论】:

      【解决方案3】:

      带有可取消包装的 Vanilla js 变体

      请注意,此解决方案不需要您修改外部 debounce 函数,甚至不需要使用外部函数。逻辑在 wrapepr 函数中完成。提供去抖代码。


      允许在其去抖动期间取消已调用函数的最简单方法是从可取消的包装中调用它。真的只需添加 3 行代码和一个可选条件。

      const doTheThingAfterADelayCancellable = debounce((filter, abort) => {
        if (abort) return
      
        // here goes your code...
        // or call the original function here
      
      }, /*debounce delay*/500)
      
      
      function onFilterChange(filter) {
        let abort = false
      
        if (filter.length < 3) { // your abort condition
          abort = true
        }
      
        // doTheThingAfterADelay(filter) // before
        doTheThingAfterADelayCancellable(filter, abort) // new wrapped debounced call
      }
      

      您可以通过abort = true 再次调用它来取消它。

      它的工作方式是清除之前的超时 fn 并像往常一样设置一个新的超时,但现在使用 if (true) return 路径。

      您也可以通过其他代码手动执行此操作...

      doTheThingAfterADelayCancellable(null, true)
      

      ...或将其包装起来并使用cancelBounce()调用

      function cancelBounce() {
        doTheThingAfterADelayCancellable(null, true)
      }
      

      作为参考,这是取自 Underscore 的经典 debounce 函数。在我的示例中它保持不变。

      // taken from Underscore.js
      // Returns a function, that, as long as it continues to be invoked, will not
      // be triggered. The function will be called after it stops being called for
      // N milliseconds. If `immediate` is passed, trigger the function on the
      // leading edge, instead of the trailing.
      export function debounce(func, wait, immediate) {
        let timeout
        return function() {
          let context = this, args = arguments
          let later = function() {
            timeout = null
            if (!immediate) func.apply(context, args)
          }
          let callNow = immediate && !timeout
          clearTimeout(timeout)
          timeout = setTimeout(later, wait)
          if (callNow) func.apply(context, args)
        }
      }
      

      【讨论】:

        【解决方案4】:

        我所做的是使用 _.mixin 创建一个 _.cancellableDebounce 方法。除了两个新行之外,它几乎与原版相同。

        _.mixin({
            cancellableDebounce: function(func, wait, immediate) {
                var timeout, args, context, timestamp, result;
        
                var later = function() {
                  var last = _.now() - timestamp;
        
                  if (last < wait && last >= 0) {
                    timeout = setTimeout(later, wait - last);
                  } else {
                    timeout = null;
                    if (!immediate) {
                      result = func.apply(context, args);
                      if (!timeout) context = args = null;
                    }
                  }
                };
        
                return function() {
                  context = this;
                  args = arguments;
                  timestamp = _.now();
                  var callNow = immediate && !timeout;
                  if (!timeout) timeout = setTimeout(later, wait);
                  if (callNow) {
                    result = func.apply(context, args);
                    context = args = null;
                  }
        
                  // Return timeout so debounced function can be cancelled
                  result = result || {};
                  result.timeout = timeout;
        
                  return result;
                };
            }
        });
        

        用法:

        var thing = function() {
            console.log("hello world");
        }
        
        var debouncedThing = _.cancellableDebounce(thing, 1000);
        var timeout = debouncedThing().timeout;
        
        clearTimeout(timeout);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-12
          • 1970-01-01
          • 1970-01-01
          • 2021-01-26
          相关资源
          最近更新 更多