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 callNowen el lugar equivocado.
javascript
debouncing
Startec
fuente
fuente

clearTimeoutcon algo que no es un ID de temporizador válido, no hace nada.WindowTimersobjeto 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 && timeoutcheque No siempre habrá untimeout(porquetimeoutse llama antes). Además, qué bien haceclearTimeout(timeout), cuando se declara (lo que lo hace indefinido) y se borra, antesimmediate && !timeoutverificación es para cuando debounce está configurado con laimmediatebandera. Esto ejecutará la función inmediatamente pero impondrá unwaittiempo de espera antes si puede ejecutarse nuevamente. Entonces, la!timeoutparte 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.setTimeoutfunción? Además, he probado este código, para mí, pasartruede 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
debounceproduce una función que está "cerrada" sobre latimeoutvariable. Latimeoutvariable permanece accesible durante cada llamada de la función producida, incluso después de quedebouncehaya regresado, y puede cambiar entre diferentes llamadas.La idea general para
debouncees la siguiente:El primer punto es solo
var timeout;, de hecho es justoundefined. Afortunadamente,clearTimeoutes bastante laxo sobre su entrada: pasar unundefinedidentificador 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
thiscontexto 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 detimeouty este valor persiste en varias llamadas a funciones. Esto permite que el rebote funcione: si la función se llama varias veces,timeoutse 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
timeoutvariable y realiza la llamada a la función real utilizando la información de la llamada almacenada.Se
immediatesupone 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:timeoutacaba de establecerse en el identificador del temporizador devuelto porsetTimeoutlo!timeoutque siempre estáfalseen 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 && !timeoutantes 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
!timeoutal 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 detimeoutpersiste en múltiples llamadas ag. El!timeoutcheque 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
setTimeoutmé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
timeoutvariable 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, eltimeoutcontenido 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
timeoutestá disponible para la próxima iteración? Y no hay ninguna razón, en mi opinión, para renombrarthisacontentyargumentsparaargs.fuente
thisy losargumentscambios 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