Как отменить отмененную функцию после ее вызова и до ее выполнения?

Я создаю debounced версию функции с подчеркиванием:

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

Как только debouncedThing вызывается...

debouncedThing();

... есть ли способ отменить его, в течение периода ожидания до его фактического выполнения?

Ответ 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

Что я сделал, используется _.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);

Ответ 3

Самый простой способ отменить уже вызванную функцию в период ее дебюта - сделать ее отмененной. На самом деле просто добавьте 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
}

Вы отменяете его, вызывая его снова с помощью abort = true.

Для справки, это ваша классическая функция debounce, взятая из Underscore. Он остается неповрежденным в моем примере.

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

Старый, но добавление примечания для всех, кто попадает сюда.

Документы (я смотрю на 1.9.1 прямо сейчас) говорят, что вы должны быть в состоянии сделать:

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

Это сделало бы то, что ОП хочет сделать (и то, что я хотел сделать). Это не будет печатать консольное сообщение.

Я никогда не мог заставить это работать. Я посмотрел высоко и низко на .cancel() как и обещал в документе Underscore, и не могу его найти.

Если вы используете Underscore, используйте опцию флага в принятом ответе Карлоса Руана. Мои требования, к сожалению (на мой взгляд), не позволяют обновить (на мой взгляд) с Underscore до Lodash. Подчеркивание имеет меньшую функциональность, но оно более функционально, чем без него.