如何延迟/开始/反跳获取数据,直到用户停止键入?

时间:2019-01-22 04:02:59

标签: javascript node.js

如果我的应用程序上有足够的用户,则每次击键发送ajax请求都是使服务器屈服的有效方法(更不用说可能会使客户端应用程序变得很迟钝了)。实现带有两个选项的符号搜索框(DB搜索和Web Api搜索)。当我在搜索框中输入符号(例如:AAPL-大量股票)时,每次通过网络发送fetch()请求。为了避免这种情况,我尝试使用setTimeout(),但是无论如何都多次发送fetch()请求。如何在用户停止输入区域以仅发送一个fetch()请求之前,延迟/开始/反跳获取请求?

HTML:

<label for="symbolTags">Symbol: </label>
  <input type="text" id="symbolTags" name="symbol">

  <label for="api">Select Search Api: </label>
  <select id="api" name="routes_api">
    <option value="search">Web Search Api</option>
    <option value="dbsearch">DB Search Api</option>
  </select>

JavaScript:

const symbolTags = document.querySelector('#symbolTags')
const symbolTagsOptions = document.querySelector('#api')

const urlsObject = {
  dbsearch: '/dbsearch/',
  search: '/search/'
}

symbolTags.oninput = function () {
  let symbolTagsOptionsValue = symbolTagsOptions.value
  let arg = urlsObject[symbolTagsOptionsValue]

  // Init a timeout variable to be used below
  let timeout = null
  // Clear the timeout if it has already been set.
  // This will prevent the previous task from executing
  // if it has been less than <MILLISECONDS>
  clearTimeout(timeout)
  // Make a new timeout set to go off in 2000ms
  timeout = setTimeout(function () {
    requestSymbolSearch(arg)
  }, 2000)
}

function requestSymbolSearch(arg) {
  getData(arg)
    .then(data => {
      console.log(data)
      $('#symbolTags').autocomplete({
        source: data.map(item => item.symbol),
        autoFocus: true
      })
    })
    .catch(error => console.error('Error:', error))
}

function getData(url) {
  let curValueSymbol = symbolTags.value
  let urlPlus = `${url}${curValueSymbol}`
  console.log(urlPlus)
  return fetchData(urlPlus)
}

async function fetchData(urlPlus) {
  const dataResponse = await fetch(urlPlus)
  const dataJson = await dataResponse.json()
  return dataJson
}

这是控制台结果:

fetch result

以下是网络结果:

enter image description here

1 个答案:

答案 0 :(得分:1)

通常通过事件 debouncing 解决此问题:

// Debounce function taken from: https://stackoverflow.com/q/24004791/1814486
function debounce(func, wait, immediate) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    var later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
};

const input = document.querySelector('#input')
  
// if there's not another `input` within 700ms, log the value,
// otherwise ignore the event.
input.addEventListener('input', debounce(() => {
  console.log(input.value)
}, 700))
<input id="input" placeholder="Type here.."/>