Estou interessado na função "debouncing" em javascript, escrita aqui: http://davidwalsh.name/javascript-debounce-function
Infelizmente, o código não é explicado com clareza suficiente para eu entender. Alguém pode me ajudar a descobrir como funciona (deixei meus comentários abaixo). Em suma, eu realmente não entendo como isso funciona
// 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);
};
};
EDIT: O trecho de código copiado anteriormente tinha callNow
no lugar errado.
javascript
debouncing
Startec
fonte
fonte
clearTimeout
com algo que não seja um ID de timer válido, ele não fará nada.WindowTimers
objeto no qual o método foi chamado, o método não fará nada".Respostas:
O código na pergunta foi ligeiramente alterado do código no link. No link, há uma verificação
(immediate && !timeout)
antes de criar um novo tempo limite. Tê-lo depois faz com que o modo imediato nunca seja acionado. Atualizei minha resposta para anotar a versão de trabalho no link.fonte
immediate && timeout
cheque. Não haverá sempre umtimeout
(porquetimeout
é chamado anteriormente). Além disso, o bom éclearTimeout(timeout)
fazer, quando é declarado (o que torna indefinido) e liberado, anteriormenteimmediate && !timeout
verificação é para quando o debounce é configurado com oimmediate
sinalizador. Isso executará a função imediatamente, mas impõe umwait
tempo limite antes, se puder ser executado novamente. Portanto, a!timeout
parte está basicamente dizendo 'desculpe, isso já foi executado dentro da janela definida' ... lembre-se de que a função setTimeout a limpará, permitindo que a próxima chamada seja executada.setTimeout
função? Além disso, eu tentei esse código para mim, passartrue
para imediato apenas impede que a função seja chamada (em vez de ser chamada após um atraso). Isso acontece para você?O importante a ser observado aqui é que
debounce
produz uma função "fechada" sobre atimeout
variável. Atimeout
variável permanece acessível durante todas as chamadas da função produzida, mesmo após odebounce
retorno, e pode alterada em diferentes chamadas.A ideia geral para
debounce
é a seguinte:O primeiro ponto é justo
var timeout;
, é de fato justoundefined
. Felizmente,clearTimeout
é bastante relaxado quanto a sua contribuição: passar umundefined
identificador de timer faz com que ele simplesmente não faça nada, não gera um erro ou algo assim.O segundo ponto é feito pela função produzida. Primeiro, ele armazena algumas informações sobre a chamada (o
this
contexto e oarguments
) em variáveis para que possa usá-las posteriormente para a chamada rejeitada. Em seguida, limpa o tempo limite (se houver um conjunto) e cria um novo para substituí-lo usandosetTimeout
. Observe que isso substitui o valor detimeout
e esse valor persiste em várias chamadas de função! Isso permite que o debounce realmente funcione: se a função for chamada várias vezes,timeout
será substituída várias vezes por um novo timer. Se não fosse esse o caso, várias chamadas causariam o início de vários temporizadores, todos permanecendo ativos - as chamadas seriam atrasadas, mas não canceladas.O terceiro ponto é feito no retorno de chamada de tempo limite. Desativa a
timeout
variável e realiza a chamada de função real usando as informações de chamada armazenadas.O
immediate
sinalizador deve controlar se a função deve ser chamada antes ou depois do timer. Se forfalse
, a função original não é chamada até depois que o timer for pressionado. Se fortrue
, a função original é chamada primeiro e não será mais chamada até que o cronômetro seja acionado.No entanto, acredito que a
if (immediate && !timeout)
verificação está errada:timeout
acabou de ser definida como o identificador de timer retornado por,setTimeout
portanto,!timeout
está semprefalse
nesse ponto e, portanto, a função nunca pode ser chamada. A versão atual do underscore.js parece ter uma verificação um pouco diferente, avaliadaimmediate && !timeout
antes da chamadasetTimeout
. (O algoritmo também é um pouco diferente, por exemplo, não usaclearTimeout
.) É por isso que você deve sempre tentar usar a versão mais recente de suas bibliotecas. :-)fonte
!timeout
no final? Por que não ele sempre existir (porque ela é definida comosetTimeout(function() etc.)
debounce
, sim, mas é compartilhado entre as chamadas para a função retornada (que é a função que você vai usar). Por exemplo, emg = debounce(f, 100)
, o valor detimeout
persiste em várias chamadas parag
. A!timeout
verificação no final é um erro, acredito, e não está no código underscore.js atual.null
. Nos meus testes com o código acima, a configuração imediata como true faz com que a função não seja chamada, como você mencionou. Qualquer solução sem sublinhado?As funções com problemas não são executadas quando invocadas, elas aguardam uma pausa de invocações por um período configurável antes de serem executadas; cada nova chamada reinicia o cronômetro.
As funções reguladas são executadas e aguardam uma duração configurável antes de serem elegíveis para disparar novamente.
Debounce é ótimo para eventos de pressionamento de tecla; quando o usuário começa a digitar e depois pausa, você envia todas as teclas pressionadas como um único evento, reduzindo assim as chamadas de manipulação.
A aceleração é ótima para terminais em tempo real que você deseja permitir que o usuário chame apenas uma vez por um período definido.
Confira também Underscore.js para as implementações.
fonte
Eu escrevi um post intitulado Demistifying Debounce in JavaScript, onde explico exatamente como uma função de debounce funciona e incluo uma demonstração.
Eu também não entendi completamente como funcionava uma função de debounce quando encontrei uma. Embora sejam relativamente pequenos, eles realmente empregam alguns conceitos avançados de JavaScript! Ter uma boa noção do escopo, dos fechamentos e do
setTimeout
método ajudará.Com isso dito, abaixo está a função básica de debounce explicada e demonstrada no meu post mencionado acima.
O produto acabado
A explicação
fonte
O que você deseja fazer é o seguinte: Se você tentar chamar uma função logo após a outra, a primeira deverá ser cancelada e a nova deverá aguardar um determinado tempo limite e depois executar. Então, com efeito, você precisa de alguma maneira de cancelar o tempo limite da primeira função? Mas como? Você poderia chamar a função e passar o id de tempo limite retornado e depois passar esse ID para quaisquer novas funções. Mas a solução acima é bem mais elegante.
O que ele faz é efetivamente disponibilizar a
timeout
variável no escopo da função retornada. Portanto, quando um evento 'redimensionar' é disparado, ele não chamadebounce()
novamente, portanto otimeout
conteúdo não é alterado (!) E ainda está disponível para a "próxima chamada de função".A principal coisa aqui é basicamente que chamamos a função interna toda vez que temos um evento de redimensionamento. Talvez seja mais claro se imaginarmos que todos os eventos de redimensionamento estão em uma matriz:
Você vê o
timeout
disponível para a próxima iteração? E não há razão, na minha opinião, de renomearthis
paracontent
earguments
paraargs
.fonte
this
e asarguments
alterações dentro da função de retorno de chamada setTimeout (). Você deve manter uma cópia em outro lugar ou essa informação será perdida.Essa é uma variação que sempre aciona a função rejeitada na primeira vez em que é chamada, com variáveis nomeadas de forma mais descritiva:
fonte
Método Debounce simples em javascript
Exemplo de tempo de execução JSFiddle: https://jsfiddle.net/arbaazshaikh919/d7543wqe/10/
fonte
Função de debounce simples: -
HTML: -
Javascript: -
fonte