Vanilla JS Debounce using API example
Published: 2023-07-11 10:14:42

## Understanding Debounce:

Debouncing refers to a technique used to optimize the execution of a function by delaying its invocation until a certain amount of time has passed. The below example demonstrates the use of debouncing in a products search functionality.

In this search products example, it's supposed to return API data based on search input. To reduce the no. of API calls, `searchProducts()` is called after a slight delay.

## HTML:

```
<!-- Search product -->
<input id="product" />

<!-- Show search results -->
<div id="search-result">
</div>
```

## JS:

The delayWrapper function is a higher-order function that creates a debounced version of the provided function func. It sets up a timer to delay the execution of func until the specified timeout period has passed.

```
const delayWrapper = (func, timeout) => {
	let timer;
  return (...args) => {
  	clearTimeout(timer);
    timer = setTimeout(() => {
      func(...args)
    }, timeout);
  }
}
```
The `delayedCall `variable is assigned the debounced version of the `searchProducts `function, created using `delayWrapper`. It has a delay of 500 milliseconds (0.5 seconds).

```
const delayedCall = delayWrapper(searchProducts, 500);
```
The `searchProducts ` function uses the provided search query q to fetch data from an API endpoint using fetch. The retrieved data is stored in products variable.

```
const searchProducts = async (q) => {
  let products = [];
  try {
    console.log(`Search param: ${q}`)
    const response = await fetch(`https://dummyjson.com/products/search?q=${q}`);
    const data = await response.json();
    products = data.products;
  } catch (e) {
    console.error('Error found: ', e);
  }
  renderProducts(products);  
}
```

The `renderProducts `function takes an array of products as a parameter and generates HTML based on the products. If there are products, it creates an unordered list ul with list items li representing each product's title. 

```
const renderProducts = (products) => {
    let searchHtml = '';
    if (products.length > 0) {
        searchHtml = '<ul>';
        products.map(prod => {
            searchHtml += `<li>${prod.title}</li>`;
        })
        searchHtml += '</ul>';
    }
    console.log('Search html', searchHtml)
    document.getElementById('search-result').innerHTML = searchHtml;
}

```

{% embed https://jsfiddle.net/ry7o2pLn/2/ %}

## Full JS Code:

```
document.getElementById('product').addEventListener('keyup', (e) => {
    delayedCall(e.target.value);
})


const searchProducts = async (q) => {
    let products = [];
    try {
        console.log(`Search param: ${q}`)
        const response = await fetch(`https://dummyjson.com/products/search?q=${q}`);
        const data = await response.json();
        console.log('API data', data)
        products = data.products;
    } catch (e) {
        console.error('Error found: ', e);
    }
    renderProducts(products);
}

const delayWrapper = (func, timeout) => {
    let timer;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            func(...args)
        }, timeout);
    }
}

const delayedCall = delayWrapper(searchProducts, 1500);

const renderProducts = (products) => {
    let searchHtml = '';
    if (products.length > 0) {
        searchHtml = '<ul>';
        products.map(prod => {
            searchHtml += `<li>${prod.title}</li>`;
        })
        searchHtml += '</ul>';
    }
    console.log('Search html', searchHtml)
    document.getElementById('search-result').innerHTML = searchHtml;
}
```