在用户连续键入时每 500 毫秒执行一次功能不超过一次

Execute a function not more than once every 500 milliseconds while user types continuously

我正在尝试实现类似自动完成的功能,所以我在 运行 在 oninput 事件触发时启用该功能。因为我正在发出获取请求而不是 运行 在每次更改时都希望它 运行 它在(可能)500 毫秒内不超过一次。有办法吗?

<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>

您好,为此使用此代码超时

    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);
    
}    

OP 的描述类似于节流行为。为了同时实现 throttled 进程及其兄弟 debounced 进程,有多种 libraries/implementations 可用。常用的有lodash and/or underscore.js.

的方法

下一个提供的示例代码使用了最初提供的 OP filterData 的模拟版本。它显示了 lodash 和两个 基本自定义 throttle/debounce 实现的不同节流和去抖行为.. .

/*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>