1

I'am trying to implement something like autocomplete, so I'am running the function when oninput event fires. Because I'am making a fetch request instead of running it on every change I'd like to run it not more than once in (maybe) 500ms. Is there a way to do this?

<body>
   <input id="input" type="text">

   <script>
      function filterData(substr) {
         fetch(url)
           .then(response => response.json())
           .then(data => {
              let filteredData = data.filter(person => person.name.includes(substr));
              print(filteredData);
            })
       }
       document.getElementById("input").oninput = (e) => filterData(e.target.value);
   </script>
</body>
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Sayid
  • 13
  • 1
  • 3

2 Answers2

1

The OP's description resembles a throttled behavior. There are various libraries/implementations available in order to achieve both the throttled process and its sibling the debounced process. Commonly used are the methods of lodash and/or underscore.js.

The next provided example code uses a mocked version of the OP's originally provided filterData. It shows the different behaviors of throttle and debounce for lodash and of two basic custom throttle/debounce implementations ...

/*function filterData(substr) {
  fetch(url)
    .then(response => response.json())
    .then(data => {
      let filteredData = data.filter(person => person.name.includes(substr));
      print(filteredData);
    });
}*/
function filterData(substr) {
  new Promise((resolve/*, reject*/) => {
  
    setTimeout(() => {
      resolve({
        search: substr,
        matches: [substr + 'Bar', substr + ' bazz', substr + ' Foooo']
      });
    }, 300);

  }).then(response => console.log({ response }));
}

function handleSearch(evt) {
  // console.log('this :', this);
  // // return filterData(this.value);
  return filterData(evt.target.value);
}

document
  .querySelector("#basicThrottled")
  .addEventListener('input', basicThrottle(handleSearch, 500));
document
  .querySelector("#basicDebounced")
  .addEventListener('input', basicDebounce(handleSearch, 500));

document
  .querySelector("#lodashThrottled")
  .addEventListener('input', _.throttle(handleSearch, 500));
document
  .querySelector("#lodashDebounced")
  .addEventListener('input', _.debounce(handleSearch, 500));
body { margin: 0; }
[type="search"] { min-width: 24%; max-width: 24%; }
.as-console-wrapper { min-height: 85%; }
<input id="basicThrottled" type="search" placeholder="basic throttled ..." />
<input id="basicDebounced" type="search" placeholder="basic debounced ..." />

<input id="lodashThrottled" type="search" placeholder="lodash throttled ..." />
<input id="lodashDebounced" type="search" placeholder="lodash debounced ..." />

<script>
function basicDebounce(proceed, delay = 300, target) {
  let timeoutId = null;

  return function debounced(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(proceed.bind(target ?? this), delay, ...args);
  };
}
function basicThrottle(proceed, threshold = 200, target) {
  let timeoutId = null;
  let referenceTime = 0;

  return function throttled(...args) {
    const currentTime = Date.now();

    if (currentTime - referenceTime >= threshold) {
      clearTimeout(timeoutId);

      referenceTime = currentTime;
      const trigger = proceed.bind((target ?? this), ...args);

      timeoutId = setTimeout((() => {

        referenceTime = 0;
        trigger();

      }), threshold);

      trigger();
    }
  };
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
-1

hi use this code timeout for that

    var timeoutId
function autoComplete(substr)
{
    
        // stop previous timeouts
        clearTimeout(timeoutId)
        timeoutId = setTimeout(function () {
         fetch(url)
           .then(response => response.json())
           .then(data => {
              let filteredData = data.filter(person => 
      person.name.includes(substr));
              print(filteredData);
            })
       });
         }, 1000);
    
}