JavaScript 디바운스를 사용하여 사용자가 입력을 중지할 때만 네트워크 요청 보내기

검색 입력이 있고 사용자로부터 keyup 이벤트를 수신한 다음 fetch() api를 사용하여 서버에 네트워크 요청을 보내야 할 때.

const searchProducts = async (e) => {
  const name = e.target.value
  const res = await fetch(`https://someapi.com/products?name=${name}`)
  const users = await res.json()
}

const input = document.querySelector('input.search')
input.addEventListener('keyup', searchProducts)


그러나 이렇게 하면 사용자가 검색 입력에 문자를 입력할 때마다 fetch() 요청을 보내게 되므로 이상적이지 않습니다. 사용자가 입력을 마쳤을 때만 검색 요청을 보내도록 코드를 리팩터링할 수 있습니다.

const searchProducts = async (e) => {
  const name = e.target.value
  const res = await fetch(`https://someapi.com/products?name=${name}`)
  const products = await res.json()
}

let timeout // 1
const debounce = (e) => {
  clearTimeout(timeout) // 3
  timeout = setTimeout(() => { // 2
    searchProducts(e.target.value)
  }, 1000)
}

const input = document.querySelector('input.search')
input.addEventListener('keyup', debounce)


저와 같은 주니어 개발자라면 이렇게 보일 수도 있습니다.
약간 혼란 스럽습니다. 여기에서 진행되는 것은 전역 변수timeout(1)를 설정한 다음 여기에 setTimeout를 할당하는 것입니다(2). 그렇지 않으면 시간 초과searchProducts()가 사용자가 입력이 완료되지 않았습니다. 즉, 사용자가 입력을 시작한 이후 1s가 지났지만 반드시 사용자가 입력을 완료했음을 의미하지는 않습니다.

우리가 그것을 볼 수 있는 또 다른 방법은 setTimeout()timeoutID를 반환한다는 것입니다.

/** 
 * assume we type our first letter in search box,
 * now debounce() will run once
 * we've set our first timeout and its timeoutID
 * will be returned and stored on timeout variable
 * timeoutID = 1 at this moment
 */
let timeout 
const debounce = (e) => {
  timeout = setTimeout(() => { // timeoutID = 1
    searchProducts(e.target.value)
  }, 1000)
}

/** 
 * now we type our second letter in search box,
 * debounce() will run again
 * we've set our second timeout and its timeoutID
 * will be returned and stored on timeout variable
 * timeoutID = 2 at this moment
 */
let timeout 
const debounce = (e) => {
  timeout = setTimeout(() => { // timeoutID = 2
    searchProducts(e.target.value)
  }, 1000)
}

// but our first timeout is still valid,
// if we don't cancel that, it will still run
// when 1s has passed since it's been created
// that is why we need to clear the timeout before 
// we set the next timeout
let timeout 
const debounce = (e) => {
  clearTimeout(timeout)
  timeout = setTimeout(() => { // timeoutID = 3
    searchProducts(e.target.value)
  }, 1000)
}


그게 다야. 도움이 되었기를 바랍니다.

좋은 웹페이지 즐겨찾기