admin管理员组

文章数量:1296485

If I get enough users on my application, sending an ajax request with each keystroke is an effective way to bring the server to its knees (not to mention possibly making the client application feel quite sluggish). On implementing a symbol search box with two options (DB Search and Web Api Search). While I am typing the symbol (ex: AAPL - aple stock) in the search box the fetch() request is sent each time over the network. To avoid it I tried to use setTimeout() but fetch() request is sent multiple times, anyway. How to delay/start/debounce fetching the request until user stops typing in input area to send only one fetch() request?

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').autoplete({
        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
}

Here is the console result:

Here is the network result:

If I get enough users on my application, sending an ajax request with each keystroke is an effective way to bring the server to its knees (not to mention possibly making the client application feel quite sluggish). On implementing a symbol search box with two options (DB Search and Web Api Search). While I am typing the symbol (ex: AAPL - aple stock) in the search box the fetch() request is sent each time over the network. To avoid it I tried to use setTimeout() but fetch() request is sent multiple times, anyway. How to delay/start/debounce fetching the request until user stops typing in input area to send only one fetch() request?

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').autoplete({
        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
}

Here is the console result:

Here is the network result:

Share Improve this question edited Jan 22, 2019 at 5:29 John John asked Jan 22, 2019 at 4:02 John JohnJohn John 1,5004 gold badges22 silver badges45 bronze badges 2
  • how about using minimum input length, For example fetch request will be made only after n number of characters entered in the input – brk Commented Jan 22, 2019 at 4:05
  • @brk the problem that it could be one letter symbol as well – John John Commented Jan 22, 2019 at 4:06
Add a ment  | 

1 Answer 1

Reset to default 9

This is monly solved by debouncing the event; which collapses multiple calls in a given timeframe to just one:

// Debounce function from: https://stackoverflow./q/24004791/1814486
const debounce = (func, wait, immediate) => {
  let timeout

  return function() {
    const context = this, args = arguments
    const later = function() {
      timeout = null
      if (!immediate) func.apply(context, args)
    }

    const callNow = immediate && !timeout
    clearTimeout(timeout)
    timeout = setTimeout(later, wait)
    if (callNow) func.apply(context, args)
  }
}
  
// If there's not another `input` within 500ms log the value,
// otherwise ignore the event.
document.querySelector('#input').addEventListener('input', debounce(() => {
  console.log(input.value)
}, 500))
<input id="input" placeholder="Type fast here.."/>

本文标签: javascriptHow to delaystartdebounce fetching data until user stops typingStack Overflow