Como implementar Debounce e Throttle com JavaScript

Em JavaScript, sempre que anexamos uma função de alto desempenho a um ouvinte de evento, considera-se uma prática recomendada controlar a frequência com que a função é chamada.

Neste tutorial, veremos como implementar as funções de debounce e de aceleração para regular eventos.

É tudo sobre desempenho

O desempenho é uma grande preocupação na construção de páginas da Web, especialmente para sites que realizam animações e interações. Os ouvintes de eventos são uma escolha comum para implementar interações com JavaScript, pois são usados ​​para detectar alterações em uma página e chamar funções de acordo com essas alterações. É importante garantir que os scripts do ouvinte de evento sejam otimizados para desempenho.

Como os Event Listeners afetam o desempenho?

Vejamos com que frequência os ouvintes de evento são chamados de acordo com as ações do usuário. Realize os eventos correspondentes na demonstração abaixo para ver a contagem:

Os ouvintes de eventos afetam o desempenho dependendo dos eventos que estão chamando.

Vamos supor que temos uma função responsável por adicionar novos elementos ao DOM e chamamos essa função toda vez que o usuário rolar. Como vimos na demonstração, o listener de evento scroll pode ser chamado cada pixel o usuário rola a tela.

Adicionar elementos ao DOM causa refluxos, que é a maneira do navegador calcular o posicionamento de novos elementos. Os refluxos são feitos em cascata, portanto, alterar o refluxo de um elemento causará uma alteração em todos os elementos subsequentes e parte ou todo o documento será renderizado novamente. Esses cálculos podem afetar a velocidade do usuário e tornar sua página mais lenta. Você pode ler mais sobre como refluxos e redesenhos afetam o desempenho neste artigo.

Sempre que estivermos anexando uma função de alto desempenho a um ouvinte de evento, é considerada uma prática recomendada controlar a frequência com que a função é chamada.

Debounce e Acelerador são dois métodos para otimizar o desempenho de scripts controlando a frequência com que um evento é chamado.

Debounce vs. Acelerador

A principal diferença entre debouncing e throttling é que o debounce chama uma função quando um usuário não realizou um evento em um período de tempo específico, enquanto o acelerador chama uma função em intervalos de um período de tempo especificado enquanto o usuário está realizando um evento.

Por exemplo, se debouncemos uma função de rolagem com um timer de 250ms (milissegundos), a função só é chamada se o usuário não tiver rolado em 250ms. Se limitarmos uma função de rolagem com um temporizador de 250 ms, a função será chamada a cada 250 ms enquanto o usuário estiver rolando.

Esta demonstração fornece uma demonstração visual do exemplo acima:

Função Debounce com Vanilla JavaScript

Vamos expandir mais sobre como o conceito de debouncing funciona.

Podemos pensar nisso como uma função de esperar para ver. Quando debounce uma função, esperamos para ver se o usuário realiza uma ação em um determinado período de tempo e, caso contrário, executamos a função. Agora vamos converter isso em lógica.

  1. Inicializar um timer variável que controla quando executar uma função de retorno de chamada
  2. Redefina a função do timer toda vez que o usuário iniciar uma ação

Aqui está a aparência da implementação da lógica:

1
let debounceTimer;
2

3
const debounce = (callback, time) => {
4
  window.clearTimeout(debounceTimer);
5
  debounceTimer = window.setTimeout(callback, time);
6
}

Neste código, inicializamos uma variável de timer chamada debounceTimer que controla um método setTimeout. Este método setTimeout é o responsável por chamar a função callback após o parâmetro especificado time.

Dentro de nossa função debounce, primeiro limpamos o debounceTimer função toda vez que a função debounce é chamada. Isso é o que garante que a função de retorno de chamada não seja chamada até que o tempo se esgote. Se definirmos a função debounce dentro de um ouvinte de evento de rolagem, o debounceTimer é redefinido por window.clearTimeout toda vez que o usuário rola.

Casos de uso para Debounce

Debouncing é um bom método para controlar eventos que requerem ações esporádicas do usuário, como digitar em um campo de entrada ou clicar em um botão. No caso de uma barra de pesquisa que faz chamadas de API de acordo com a entrada do usuário, implementar um debounce é uma boa maneira de reduzir o número de chamadas feitas à API.

Nesta demonstração, reduzimos a entrada do usuário para retornar apenas o valor de entrada se o usuário não tiver digitado nada em 500 ms:

Podemos escrever o código para a demonstração acima assim:

1
let input = document.getElementById('name');
2
let debounceValue = document.getElementById('debounce-value');
3

4
const updateDebounceValue = () => {
5
  debounceValue.innerHTML = input.value;
6
}
7

8
let debounceTimer;
9

10
const debounce = (callback, time) => {
11
  window.clearTimeout(debounceTimer);
12
  debounceTimer = window.setTimeout(callback, time);
13
};
14

15
input.addEventListener(
16
  "input",
17
  () => {
18
    debounce(updateDebounceValue, 500)
19
  },
20
  false
21
);

Implemente uma função de aceleração com JavaScript Vanilla

Podemos pensar no acelerador como um minimizando função; minimiza o número de chamadas feitas dentro de um determinado intervalo de tempo.

Definindo a lógica para um acelerador, temos:

  1. Inicializa uma variável para detectar se a função foi chamada dentro do tempo especificado
  2. Se a função foi chamada, pause a função de aceleração
  3. Se a função não foi chamada ou foi executada no intervalo, execute novamente a função de aceleração

Podemos escrever isso em JavaScript como:

1
//initialize throttlePause variable outside throttle function

2
let throttlePause;
3

4
const throttle = (callback, time) => {
5
  //don't run the function if throttlePause is true

6
  if (throttlePause) return;
7

8
  //set throttlePause to true after the if condition. This allows the function to be run once

9
  throttlePause = true;
10
  
11
  //setTimeout runs the callback within the specified time

12
  setTimeout(() => {
13
    callback();
14
    
15
    //throttlePause is set to false once the function has been called, allowing the throttle function to loop

16
    throttlePause = false;
17
  }, time);
18
};

Aqui está um resumo do que está acontecendo:

  1. throttlePause é inicialmente indefinido, então a função passa para a próxima linha.
  2. Montamos throttlePause para true para a próxima iteração. Se a função de aceleração for chamada novamente antes setTimer é feito, a função retorna indefinido.
  3. setTimeout inicia um temporizador para executar a função. O cronômetro é executado de forma assíncrona enquanto a função de aceleração está sendo chamada para que não seja afetado pela função de aceleração sendo chamada novamente.
  4. Depois que o retorno de chamada foi executado, ele define throttlePause para false para que a função do acelerador possa fazer um loop.

Casos de uso para acelerador

O acelerador é útil para casos em que o usuário está realizando um evento suave ou contínuo, como rolagem ou redimensionamento. No caso de animar elementos com base em sua posição de rolagem ou manipular uma página de rolagem infinita, podemos usar o acelerador para controlar a frequência com que o manipulador de rolagem é chamado.

Nesta demonstração, definimos uma função de aceleração em um ouvinte de evento de rolagem:

O código para a demonstração acima se parece com isso:

1
let throttleTimer;
2

3
const throttle = (callback, time) => {
4
  if (throttleTimer) return;
5
    throttleTimer = true;
6
    setTimeout(() => {
7
        callback();
8
        throttleTimer = false;
9
    }, time);
10
}
11

12
window.addEventListener("scroll", () => { 
13
  throttle(handleScrollAnimation, 250);
14
});

Conclusão

Agora você deve ter um melhor entendimento dos conceitos e diferenças entre acelerador e debounce. Também exploramos as abordagens lógicas e a implementação de código de ambos os métodos para que você possa aplicá-los a situações da vida real para otimizar o desempenho de seus scripts.

Saiba mais sobre JavaScript front-end

De conceitos iniciantes a projetos práticos, oferecemos a você:

[ad_2]

Deixe uma resposta