Estoy interesado en la función "antirrebote" en javascript, escrito aquí: http://davidwalsh.name/javascript-debounce-function
Lamentablemente, el código no se explica con suficiente claridad para que yo lo entienda. ¿Alguien puede ayudarme a entender cómo funciona? (Dejé mis comentarios a continuación). En resumen, realmente no entiendo cómo funciona esto
// 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.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
EDITAR: el fragmento de código copiado anteriormente se encontraba callNow
en el lugar equivocado.
javascript
debouncing
Startec
fuente
fuente
clearTimeout
con algo que no es un ID de temporizador válido, no hace nada.WindowTimers
objeto en el que se invocó el método, el método no hace nada".Respuestas:
El código en la pregunta fue alterado ligeramente del código en el enlace. En el enlace, hay
(immediate && !timeout)
una marca ANTES de crear un nuevo tiempo de espera. Tenerlo después hace que el modo inmediato nunca se dispare. He actualizado mi respuesta para anotar la versión de trabajo desde el enlace.fuente
immediate && timeout
cheque No siempre habrá untimeout
(porquetimeout
se llama antes). Además, qué bien haceclearTimeout(timeout)
, cuando se declara (lo que lo hace indefinido) y se borra, antesimmediate && !timeout
verificación es para cuando debounce está configurado con laimmediate
bandera. Esto ejecutará la función inmediatamente pero impondrá unwait
tiempo de espera antes si puede ejecutarse nuevamente. Entonces, la!timeout
parte básicamente dice 'lo siento bub, esto ya se ejecutó dentro de la ventana definida' ... recuerda que la función setTimeout lo borrará, permitiendo que se ejecute la próxima llamada.setTimeout
función? Además, he probado este código, para mí, pasartrue
de inmediato solo evita que se llame a la función (en lugar de que se llame después de un retraso). ¿Esto te pasa a ti?Lo importante a tener en cuenta aquí es que
debounce
produce una función que está "cerrada" sobre latimeout
variable. Latimeout
variable permanece accesible durante cada llamada de la función producida, incluso después de quedebounce
haya regresado, y puede cambiar entre diferentes llamadas.La idea general para
debounce
es la siguiente:El primer punto es solo
var timeout;
, de hecho es justoundefined
. Afortunadamente,clearTimeout
es bastante laxo sobre su entrada: pasar unundefined
identificador de temporizador hace que simplemente no haga nada, no arroja un error o algo así.El segundo punto lo realiza la función producida. Primero almacena cierta información sobre la llamada (el
this
contexto y elarguments
) en variables para que luego pueda usarla para la llamada sin rebote. Luego borra el tiempo de espera (si había un conjunto) y luego crea uno nuevo para reemplazarlo usandosetTimeout
. Tenga en cuenta que esto sobrescribe el valor detimeout
y este valor persiste en varias llamadas a funciones. Esto permite que el rebote funcione: si la función se llama varias veces,timeout
se sobrescribe varias veces con un nuevo temporizador. Si este no fuera el caso, varias llamadas provocarían que se iniciaran múltiples temporizadores, todos los cuales permanecerían activos; las llamadas simplemente se retrasarían, pero no se cancelarían.El tercer punto se realiza en la devolución de llamada de tiempo de espera. Desarma la
timeout
variable y realiza la llamada a la función real utilizando la información de la llamada almacenada.Se
immediate
supone que la bandera controla si la función debe llamarse antes o después del temporizador. Si se tratafalse
, la función original no se conoce hasta después de que el temporizador es golpeado. Si es asítrue
, primero se llama a la función original y no se volverá a llamar hasta que se toque el temporizador.Sin embargo, creo que la
if (immediate && !timeout)
verificación es incorrecta:timeout
acaba de establecerse en el identificador del temporizador devuelto porsetTimeout
lo!timeout
que siempre estáfalse
en ese punto y, por lo tanto, la función nunca se puede llamar. La versión actual de underscore.js parece tener una comprobación ligeramente diferente, donde se evalúaimmediate && !timeout
antes de llamarsetTimeout
. (El algoritmo también es un poco diferente, por ejemplo, no se usaclearTimeout
). Es por eso que siempre debe intentar usar la última versión de sus bibliotecas. :-)fuente
!timeout
al final? ¿Por qué no siempre existe (porque está configurado comosetTimeout(function() etc.)
debounce
, sí, pero se comparte entre las llamadas a la función devuelta (que es la función que va a utilizar). Por ejemplo, eng = debounce(f, 100)
, el valor detimeout
persiste en múltiples llamadas ag
. El!timeout
cheque al final es un error, creo, y no está en el código actual de subrayado.js.null
. En mis pruebas con el código anterior, establecer inmediatamente en verdadero hace que la función no llame en absoluto, como usted mencionó. ¿Alguna solución sin guión bajo?Las funciones rechazadas no se ejecutan cuando se invocan, esperan una pausa de invocaciones durante una duración configurable antes de ejecutarse; cada nueva invocación reinicia el temporizador.
Las funciones reguladas se ejecutan y luego esperan una duración configurable antes de ser elegibles para disparar nuevamente.
Debounce es ideal para eventos de pulsación de teclas; cuando el usuario comienza a escribir y luego hace una pausa, envía todas las pulsaciones de teclas como un solo evento, reduciendo así las invocaciones de manejo.
Throttle es ideal para puntos finales en tiempo real que solo desea permitir que el usuario invoque una vez por un período de tiempo establecido.
Echa un vistazo a Underscore.js para sus implementaciones también.
fuente
Escribí una publicación titulada Demistifying Debounce en JavaScript donde explico exactamente cómo funciona una función antirrebote e incluyo una demostración.
Yo tampoco entendí completamente cómo funcionaba una función antirrebote cuando la encontré por primera vez. Aunque son relativamente pequeños, ¡en realidad emplean algunos conceptos JavaScript bastante avanzados! Tener un buen control del alcance, los cierres y el
setTimeout
método ayudarán.Dicho esto, a continuación se explica y se muestra la función básica antirrebote en mi publicación mencionada anteriormente.
El producto terminado
La explicación
fuente
Lo que desea hacer es lo siguiente: si intenta llamar a una función inmediatamente después de otra, la primera debe cancelarse y la nueva debe esperar un tiempo de espera determinado y luego ejecutarse. Entonces, ¿en efecto necesita alguna forma de cancelar el tiempo de espera de la primera función? ¿Pero cómo? Usted podria llamar a la función, y pasar el tiempo de espera de regresar-id y luego pasar esa identificación en cualquier nueva función. Pero la solución anterior es mucho más elegante.
Lo que hace es que la
timeout
variable esté efectivamente disponible en el alcance de la función devuelta. Entonces, cuando se activa un evento de 'cambio de tamaño', nodebounce()
vuelve a llamar , por lo tanto, eltimeout
contenido no se modifica (!) Y aún está disponible para la "próxima llamada de función".La clave aquí es básicamente que llamamos a la función interna cada vez que tenemos un evento de cambio de tamaño. Quizás sea más claro si imaginamos que todos los eventos de cambio de tamaño están en una matriz:
¿Ves que
timeout
está disponible para la próxima iteración? Y no hay ninguna razón, en mi opinión, para renombrarthis
acontent
yarguments
paraargs
.fuente
this
y losarguments
cambios dentro de la función de devolución de llamada setTimeout (). Tienes que guardar una copia en otro lugar o esa información se perderá.Esta es una variación que siempre activa la función sin rebote la primera vez que se llama, con variables más descriptivas:
fuente
Método de rebote simple en javascript
Ejemplo de tiempo de ejecución JSFiddle: https://jsfiddle.net/arbaazshaikh919/d7543wqe/10/
fuente
Función antirrebote simple: -
HTML: -
Javascript: -
fuente