Com a web se tornando cada vez mais uma plataforma em tempo real, a necessidade de oferecer aos usuários uma experiência de satisfação imediata cresceu exponencialmente.
A jornada de tentar atender a essas demandas deu a nós, desenvolvedores, uma série de desafios, desde questões de desempenho, assíncronas e de gerenciamento de estado. Embora este ProTip não cubra a amplitude desses desafios, ele cobrirá a otimização assíncrona por meio de depuração!
Debouncing é a prática de reduzir a sobrecarga de HTTP ao trabalhar com interações imediatas.
O cenário mais comum é atualizar um registro com dados de um formulário da web sem o uso de um botão de envio. Você pode imaginar, dependendo do escopo do campo de entrada e da velocidade de digitação do usuário, a quantidade de solicitações HTTP como resultado disso pode ser substancial. Imagine se seu site tivesse milhares de usuários simultâneos preenchendo este formulário. Você está basicamente fazendo DDoS em seus próprios servidores!
Pesquisar na web fornecerá vários sistemas de eliminação de pontos, todos com um sabor ligeiramente diferente. Embora eu ache que essa é uma parte muito legal da comunidade JS, falarei sobre um dos métodos que considero mais eficientes e fáceis de implementar: o cronômetro.
O método do cronômetro pode ser pensado da seguinte maneira:
- Coloque um minuto no relógio.
- Designe uma ação específica que, quando acionada, zera o relógio.
- Designe uma ação específica que seja acionada quando o relógio acabar.
- Comece o relógio.
- Redefina o relógio para um estado parado, mas pronto quando acabar.
Em nosso caso, um minuto é muito tempo para esperar que um usuário espere a atualização de um registro ou algo do gênero.
Vamos configurá-lo para 100 milissegundos.
Aqui está a aparência do código acima.
// Let’s create a namespace for our time related functions.
var Timer = {};
// Debounce Interval, in ms. It’s a good idea to make something like this “implementer configurable”. This is the equivalent of “putting a minute on the clock".
Timer.debounceInterval = 100;
// Time value that gets manipulated
Timer.currentTime;
// Store the setInterval function
Timer.interval;
// Create a pointer to a function that gets called when the timer runs out.
// Be sure to only point to a reference, and not () an execution.
Timer.onTimeout = foo;
// This is the equivalent of running the clock and would be the callback of your registered event handler.
// The 'data' argument more or less represents an event object from the aforementioned handler.
Timer.run = function(data) {
var self = this;
// Set/reset time.
this.currentTime = this.debounceInterval;
// Prevent the current interval from running out - this isn’t technically necessary with the current code, but it helps me feel like I’m covering a potential gap.
clearInterval(self.interval);
// Create a new one.
// We use setInterval here to get as close to a 1ms representation as possible.
this.interval = setInterval(function() {
// Decrement time
self.currentTime--;
// Check for timeout. Since zero is falsy we can get away with just doing this:
if(!self.currentTime) {
// Run the callback
self.onTimeout(data);
// If it timesout, clear the interval
clearInterval(self.interval);
}
}, 1);
};
Isso é realmente o mais complexo possível!
Para obter um exemplo de implementação, consulte este violino: http://jsfiddle.net/ktstowell/6cmLG/