javascript 如何在调用后和执行前取消去抖动函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29012922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 09:57:48  来源:igfitidea点击:

How to cancel a debounced function after it is called and before it executes?

javascriptunderscore.js

提问by user1031947

I create a debounced version of a function with underscore:

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

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

Once debouncedThing is called...

一旦 debouncedThing 被调用...

debouncedThing();

...is there any way to cancel it, during the wait period before it actually executes?

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

回答by Carlos Ruana

If you use the last version of lodash you can simply do:

如果您使用 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()

Another solution is with a flag:

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

// 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;

回答by Dexygen

What I've done is used _.mixin to create a _.cancellableDebounce method. It's nearly identical to the original except for two new lines.

我所做的是使用 _.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;
        };
    }
});

USAGE:

用法:

var thing = function() {
    console.log("hello world");
}

var debouncedThing = _.cancellableDebounce(thing, 1000);
var timeout = debouncedThing().timeout;

clearTimeout(timeout);

回答by Qwerty

The easiest way to cancel an already called function within its debounce period is to make it cancelable. Really just add 3 lines of code and one condition.

在去抖动周期内取消已调用函数的最简单方法是使其可取消。实际上只需添加 3 行代码和一个条件。

const doTheThingAfterADelay = debounce((filter, abort) => {
  if (abort) return

  // here goes your code...

}, /*debounce delay*/500)


function onFilterChange(filter) {
  let abort = false

  if (filter.length < 3) { // your abort condition
    abort = true
  }

  doTheThingAfterADelay(filter, abort) // debounced call
}

You cancel it by calling it again with abort = true.

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

For reference, this is your classic debouncefunction taken from Underscore. It remains intact in my example.

// 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)
  }
}

作为参考,这是您debounceUnderscore. 在我的例子中它保持不变。

// 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)
  }
}

回答by Stephan Samuel

Old, but adding a note for anyone else who gets here.

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

The docs (I'm looking at 1.9.1 right now) say that you should be able to do:

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

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

This would do the thing that the OP wants to do (and what I wanted to do). It would not print the console message.

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

I have never been able to get this to work. I have looked high and low for a .cancel()as promised in the Underscore doc and I cannot find it.

我从来没有能够让它发挥作用。我已经.cancel()按照 Underscore 文档中的承诺寻找了高低,但我找不到它。

If you are using Underscore, use the flag option in the accepted answer by Carlos Ruana. My requirements lamentably (in my opinion) do not allow an upgrade (in my opinion) from Underscore to Lodash. Underscore has less functionality but it is more functional than without.

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