Aprenda a função JavaScript Debounce criando o aplicativo de pesquisa da Wikipedia

Resumo : neste tutorial, você aprenderá sobre a função debounce do JavaScript e como usá-la para melhorar o desempenho do aplicativo.

Para entender a função debounce, você criará um aplicativo de pesquisa da Wikipédia usando a técnica de programação debounce.

Crie a estrutura de pastas do projeto

Primeiro, crie uma nova pasta chamada wikipedia-searchque irá armazenar os arquivos dos projetos.

Segundo, crie três pastas dentro da wikipedia-searchpasta chamada js, csse img. Essas pastas armazenarão arquivos JavaScript, CSS e imagens de acordo.

Terceiro, crie o style.cssna csspasta e no app.jstambém js, baixe a imagem a seguir e copie-a para a imgpasta. Você usará o logotipo para criar a interface do aplicativo.

Finalmente, crie um index.htmlarquivo na pasta raiz.

A estrutura do projeto ficará assim:

Construa a página HTML

Abra o arquivo index.html e adicione o seguinte código:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Wikipedia Search</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <header>
        <img src="./img/wikipedia-logo.png" alt="wikipedia">
        <h1>Wikipedia Search</h1>
        <input type="text" name="searchTerm" id="searchTerm" placeholder="Enter a search term...">
    </header>
    <main id="searchResult"></main>
    <script src="js/app.js"></script>
</body>
</html>Linguagem de código:  HTML, XML  ( xml )

Neste arquivo HTML:

  • Primeiro, crie um link para o style.cssarquivo na <head>seção.
  • Segundo, adicione uma <script>tag srcvinculada ao app.jsarquivo e coloque-a logo antes da </body>tag.
  • Terceiro, adicione duas seções ao corpo da página HTML. A primeira seção é o cabeçalho que mostra o logotipo da Wikipedia, o título e a caixa de pesquisa. A segunda seção inclui a <main>tag que exibirá o resultado da pesquisa.

Copie o código CSS

Navegue até o arquivo style.css , copie seu código e cole-o no style.cssarquivo da csspasta. Ao abrir o index.htmlarquivo, você deverá ver algo como a página a seguir .

Lidar com eventos de entrada

Primeiro, selecione os <input>elementos do resultado da pesquisa usando o querySelector()método:

const searchTermElem = document.querySelector('#searchTerm');
const searchResultElem = document.querySelector('#searchResult');Linguagem de código:  JavaScript  ( javascript )

Segundo, defina o foco no <input>elemento chamando o focus()método:

searchTermElem.focus();Linguagem de código:  CSS  ( css )

Terceiro, anexe um inputouvinte de evento para o <input>elemento:

searchTermElem.addEventListener('input', function (event) {
    console.log(event.target.value);
});Linguagem de código:  JavaScript  ( javascript )

Se você digitar algum texto no <input>elemento, verá que inputocorre o evento, que mostra o texto para o Console.

Por exemplo, quando você digita the debounceno <input>elemento:

… você verá os seguintes textos no console:

Obtenha resultados de pesquisa usando a API Wikipedia

A API da Wikipedia é bastante simples. Não requer uma chave de API.

Para obter os tópicos por um termo de pesquisa, você precisa anexar o srsearchparâmetro de consulta:

&srsearch=<searchTerm>Linguagem de código:  HTML, XML  ( xml )

para o seguinte URL:

https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10Linguagem de código:  JavaScript  ( javascript )

… e envie uma GETsolicitação HTTP.

Por exemplo, você pode obter os tópicos relacionados à debouncepalavra-chave enviando uma GETsolicitação HTTP para o seguinte URL:

https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=debounceLinguagem de código:  JavaScript  ( javascript )

A propósito, você pode abrir o URL acima no navegador para ver a resposta.

Em JavaScript, você pode usar a API fetch , que está disponível em todos os navegadores modernos, para enviar uma GETsolicitação HTTP.

O seguinte cria a search()função que aceita um termo de pesquisa, faz uma GETsolicitação HTTP para a Wikipedia e mostra os resultados da pesquisa para o Console:

const search = async (searchTerm) => {
    try {
        const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=${searchTerm}`;
        const response = await fetch(url);
        const searchResults = await response.json();

        // show the search result in the console
        console.log({
            'term': searchTerm,
            'results': searchResults.query.search
        });

    } catch (error) {
        console.log(error);
    }
}Linguagem de código:  JavaScript  ( javascript )

Como funciona.

Primeiro, construa o URL da API adicionando o srsearchparâmetro de consulta ao endpoint:

const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=${searchTerm}`;Linguagem de código:  JavaScript  ( javascript )

Segundo, use o fetch()método para enviar uma GETsolicitação HTTP. Como o fetch()método retorna uma promessa, você precisa usar awaituma palavra-chave para aguardar a resposta.

A promessa retornada pela fetch()função possui muitos métodos, um deles é json(). O json()método também retorna outra promessa que resulta em um resultado no formato JSON.

Por causa da awaitpalavra-chave, você precisa marcar a search()função asynccomo esta:

const search = async (searchTerm) = {
   /// ...
};Linguagem de código:  JavaScript  ( javascript )

O objeto retornado do json()método possui muitas propriedades. E para obter os resultados da pesquisa, você precisa acessar o searchResults.query.searchimóvel.

Para testar o search()método, chame-o no inputouvinte de eventos da seguinte maneira:

searchTermElem.addEventListener('input', function (event) {
    search(event.target.value);
});Linguagem de código:  JavaScript  ( javascript )

A seguir mostra o app.jsarquivo completo:

const searchTermElem = document.querySelector('#searchTerm');
const searchResultElem = document.querySelector('#searchResult');

searchTermElem.select();

searchTermElem.addEventListener('input', function (event) {
    search(event.target.value);
});

const search = async (searchTerm) => {
    try {
        const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=${searchTerm}`;
        const response = await fetch(url);
        const searchResults = await response.json();

        // show the search result in the console
        console.log({
            'term': searchTerm,
            'results': searchResults.query.search
        });

    } catch (error) {
        console.log(error);
    }
}Linguagem de código:  JavaScript  ( javascript )

Agora, se você abrir o index.htmlarquivo e digitar a debouncepalavra-chave no elemento input, verá os seguintes resultados no Console:

A saída indica que a search()função é executada para cada caractere digitado. Chama a API para cada entrada de texto, o que não é eficiente.

Para limitar o número de solicitações, você enviará solicitações de API somente quando necessário. Em outras palavras, você enviará uma solicitação de API somente depois que os usuários pausarem ou pararem de digitar por um período de tempo, por exemplo, meio segundo.

Para fazer isso, você pode usar setTimeout() e clearTimeout()função:

  • Quando os usuários digitam um caractere, use a setTimeout()função para agendar a execução da função search() após um período de tempo.
  • Se os usuários continuarem digitando, cancele o cronômetro usando a clearTimeout()função. Caso o usuário pause ou pare de digitar, deixe o cronômetro executar a função agendada de busca.

O seguinte mostra a nova versão da search()função:


let timeoutId;

const search = (searchTerm) => {
    // reset the previous timer
    if (timeoutId) {
        clearTimeout(timeoutId);
    }

    // set up a new timer
    timeoutId = setTimeout(async () => {
        try {
            const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=${searchTerm}`;
            const response = await fetch(url);
            const searchResults = await response.json();

            // show the search result in the console
            console.log({
                'term': searchTerm,
                'results': searchResults.query.search
            });
        } catch (error) {
            console.log(error);
        }
    }, 500);
};Linguagem de código:  JavaScript  ( javascript )

Como o awaitcódigo relacionado é movido para a função de retorno de chamada do setTimeout(), você precisa marcar o retorno de chamada com a asyncpalavra-chave e remover a asyncpalavra-chave da search()função.

Se você abrir o index.htmlarquivo no navegador da web e digitar a palavra-chave debounce sem pausar (por meio segundo) e parar, verá que o aplicativo fará apenas uma solicitação de API.

E essa técnica é conhecida como debouncing .

O que é debouncing

Se você tiver uma tarefa demorada, como uma solicitação de API disparada com frequência, isso afetará o desempenho do aplicativo.

Debouncing é uma técnica de programação que limita o número de vezes que uma função é chamada.

Desenvolva uma função debounce reutilizável

A debounce()função precisa aceitar uma função ( fn), limitar o número de chamadas a ela e retornar uma função:

const debounce = (fn) => {
   return (arg) => {
      // logic to limit the number of call fn
      fn(arg);
   };
};Linguagem de código:  JavaScript  ( javascript )

O seguinte usa as funções clearTimeout()e setTimeout()para eliminar a fnfunção:

const debounce = (fn) => {
    let timeoutId;

    return (arg) => {
        // cancel the previous timer
        if (timeoutId) {
            clearTimeout(timeoutId);
        }
        // setup a new timer
        timeoutId = setTimeout(() => {
            fn(arg);
        }, 500);
    };
};Linguagem de código:  JavaScript  ( javascript )

Normalmente, a fnfunção aceitará mais de um argumento. Para invocar a fnfunção com uma lista de argumentos, você usa o apply()método:

const debounce = (fn, delay=500) => {
    let timeoutId;

    return (...args) => {
        // cancel the previous timer
        if (timeoutId) {
            clearTimeout(timeoutId);
        }
        // setup a new timer
        timeoutId = setTimeout(() => {
            fn.apply(null, args);
        }, delay);
    };
};Linguagem de código:  JavaScript  ( javascript )

Como funciona:

  • Primeiro, substitua o número codificado 500pelo delayargumento para que você possa especificar quanto tempo esperar antes de executar a fnfunção. O valor padrão do atraso é 500 ms.
  • Segundo, adicione the ...argsà função retornada. O ...argé um parâmetro rest que permite coletar todos os argumentos da fn()função em um array args.
  • Terceiro, fn.apply(null, args)executa a fn()função com os argumentos especificados no argsarray.

Use a função de rejeição

O seguinte remove a lógica de depuração da search()função e usa a debounce()função:

const search = debounce(async (searchTerm) => {
    try {
        const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=${searchTerm}`;
        const response = await fetch(url);
        const searchResults = await response.json();

        // show the search result in the console
        console.log({
            'term': searchTerm,
            'results': searchResults.query.search
        });
    } catch (error) {
        console.log(error);
    }
});Linguagem de código:  JavaScript  ( javascript )

Converta os resultados da pesquisa em HTML

Mostraremos o título e o snippet de cada resultado da pesquisa na saída. Antes de fazer isso, precisaremos de algumas funções utilitárias:

Tira tags HTML

O titlee snippetdo resultado da pesquisa da chamada de API pode conter tags HTML. E é seguro remover todas as tags HTML antes de renderizá-las.

A seguinte função utilitária retira as tags HTML de uma string:

const stripHtml = (html) => {
    let div = document.createElement('div');
    div.textContent = html;
    return div.textContent;
};
Linguagem de código:  JavaScript  ( javascript )

A stripHtml()função aceita uma string HTML. Ele cria um <div>elemento temporário, atribui innerHTMLa string HTML e retorna sua textContentpropriedade.

Observe que esta função só funcionará em navegadores da web porque depende da API DOM do navegador da web.

Destaque o termo de pesquisa

É mais intuitivo se os termos da pesquisa estiverem destacados no resultado da pesquisa.

Esta highlight()função destaca todas as ocorrências de keywordin str, envolvendo cada ocorrência da palavra-chave em uma <span>tag com a highlightclasse:

const highlight = (str, keyword, className = "highlight") => {
    const hl = `<span class="${className}">${keyword}</span>`;
    return str.replace(new RegExp(keyword, 'gi'), hl);
};Linguagem de código:  JavaScript  ( javascript )

Observe que a função usa a expressão regular para substituir todas as ocorrências de keywordpelo <span>elemento.

Converta os resultados da pesquisa em HTML

A generateSearchResultHTML()função a seguir converte os resultados da pesquisa em HTML:


const generateHTML= (results, searchTerm) => {
    return results
        .map(result => {
            const title = highlight(stripHtml(result.title), searchTerm);
            const snippet = highlight(stripHtml(result.snippet), searchTerm);

            return `<article>
                <a href="https://en.wikipedia.org/?curid=${result.pageid}">
                    <h2>${title}</h2>
                </a>
                <div class="summary">${snippet}...</div>
            </article>`;
        })
        .join('');
}Linguagem de código:  JavaScript  ( javascript )

Como funciona.

  • Primeiro, use o map()método para retornar a representação HTML de cada resultado da pesquisa e o join()método para unir os resultados da pesquisa (em formato HTML) em uma única string HTML.
  • Em segundo lugar, retire as tags HTML e destaque o termo de pesquisa titlee snippetretorne da chamada de API.

Mostrar os resultados da pesquisa

Altere o search()método que usa a generateSearchResultHTML()função e anexe seu resultado ao arquivo searchResultElem. Além disso, redefina o resultado da pesquisa se o termo de pesquisa estiver vazio:

const search = debounce(async (searchTerm) => {

    // if the search term is removed, 
    // reset the search result
    if (!searchTerm) {
        // reset the search result
        searchResultElem.innerHTML = '';
        return;
    }

    try {
        // make an API request
        const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=${searchTerm}`;
        const response = await fetch(url);
        const searchResults = await response.json();

        // render search result
        const searchResultHtml = generateSearchResultHTML(searchResults.query.search, searchTerm);

        // add the search result to the searchResultElem
        searchResultElem.innerHTML = searchResultHtml;
    } catch (error) {
        console.log(error);
    }
});Linguagem de código:  JavaScript  ( javascript )

Agora, se você abrir no index.htmlnavegador da web, verá o aplicativo funcionando.

Resumo

Neste tutorial, você aprendeu os seguintes pontos principais:

  • Use a fetch()API para fazer GETsolicitações HTTP.
  • Use as async/awaitpalavras-chave para deixar o código assíncrono mais limpo.
  • Compreenda a técnica de programação de debouncing e desenvolva uma debounce()função JavaScript reutilizável.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *