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

北城余情 提交于 2019-12-20 10:23:03

问题


I create a debounced version of a function with underscore:

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

Once debouncedThing is called...

debouncedThing();

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


回答1:


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

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



回答2:


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: 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);



回答3:


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.

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.

For reference, this is your classic debounce function 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)
  }
}



回答4:


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:

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.

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.

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.



来源:https://stackoverflow.com/questions/29012922/how-to-cancel-a-debounced-function-after-it-is-called-and-before-it-executes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!