javascript - ¿Cómo cancelar una función de rebote después de que se llama y antes de que se ejecute?
underscore.js (3)
La forma más fácil de cancelar una función ya llamada dentro de su período de rebote es hacerlo cancelable. Realmente solo agregue 3 líneas de código y una condición.
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
}
Lo cancelas llamándolo de nuevo con abort = true
.
Para referencia, esta es su función de
debounce
clásica tomada desde eldebounce
bajo. Permanece intacto en mi ejemplo.
// 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) } }
Creo una versión con rebote de una función con un guión bajo:
var debouncedThing = _.debounce(thing, 1000);
Una vez que se llama debouncThing se llama ...
debouncedThing();
... ¿hay alguna forma de cancelarlo, durante el período de espera antes de que se ejecute?
Lo que he hecho es usar _.mixin para crear un método _.cancellableDebounce. Es casi idéntico al original, excepto por dos nuevas líneas.
_.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;
};
}
});
USO:
var thing = function() {
console.log("hello world");
}
var debouncedThing = _.cancellableDebounce(thing, 1000);
var timeout = debouncedThing().timeout;
clearTimeout(timeout);
Si usas la última versión de lodash puedes simplemente hacer:
// 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()
Otra solución es con una bandera:
// 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;