JavaScript

Throttle & Debounce

kelly09 2024. 6. 30. 10:33

๐Ÿฐ ๋‘˜ ๋‹ค JavaScript์—์„œ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ํŠน์ • ์ด๋ฒคํŠธ์˜ ํ˜ธ์ถœ ๋นˆ๋„๋ฅผ ์ œ์–ดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋จ.

๐Ÿด Throttle

: ์ด๋ฒคํŠธ๊ฐ€ ์—ฐ์†ํ•ด์„œ ๋ฐœ์ƒ ์‹œ, ์ผ์ • ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์œผ๋กœ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•จ.

  • ์ด๋ฒคํŠธ๊ฐ€ ์ž์ฃผ ๋ฐœ์ƒํ•ด๋„ ์ผ์ • ์‹œ๊ฐ„๋งˆ๋‹ค ํ•œ ๋ฒˆ์”ฉ๋งŒ ์ฒ˜๋ฆฌ๋จ.
 let waiting = false;
 
function throttle(callback, limit = 200) {

    if (!waiting) { // waiting์ด false์ผ ๋•Œ๋งŒ ์‹คํ–‰
      callback();
      waiting = true;

      setTimeout(() => { // limit์ดˆ ๋’ค์— waiting์„ false๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ํƒ€์ด๋จธ
        waiting = false;
      }, limit);
    }
}
  • ํƒ€์ด๋จธ๊ฐ€ ๋Œ๊ณ  ์žˆ๋Š” ์™€์ค‘์— throttle ํ•จ์ˆ˜๋ฅผ ๊ณ„์† ํ˜ธ์ถœํ•ด๋„ waiting์ด true๋‹ˆ๊นŒ ๋‚˜๋จธ์ง€๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์Œ
  • limit์ดˆ๊ฐ€ ์ง€๋‚œ ํ›„ waiting์ด false๊ฐ’์ด ๋˜๋ฉด ๋‹ค์‹œ if๋ฌธ์„ ๋Œ๋ฉด์„œ callback()์„ ๋‹ค์‹œ ์‹คํ–‰์‹œํ‚ด
  • ๋‹ค์‹œ ํƒ€์ด๋จธ๊ฐ€ ๋Œ์•„๊ฐ€๊ณ  ๋ฐ˜๋ณต...

์œ„ ํ•จ์ˆ˜๋ฅผ closure๋กœ ์ˆ˜์ •!

const ground = document.querySelector(".ground");

let waiting = false;

function throttle(callback) {
  if (!waiting) {
    callback();
    waiting = true;

    setTimeout(() => {
      waiting = false;
    }, 1000);
  }
}
ground.addEventListener("mousemove", (e) => { // event ๊ฐ์ฒด ์ „๋‹ฌํ•˜๋ฉด throttle()์˜ ์•ˆ์ชฝ ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋“ค์–ด๊ฐ€์„œ
// throttle์—์„œ ๋ฐ›์•„์„œ ์“ธ ์ˆ˜ ์žˆ์Œ
  console.log(e);
});
  • ํ•จ์ˆ˜๋ฅผ returnํ•˜๋Š” ํ˜•์‹
  • throttle()์„ ์‹คํ–‰์‹œํ‚ด => ์•ˆ์ชฝ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋จ => ์•ˆ์ชฝ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œ์ผœ์•ผ ํ•จ! throttle(()=>{
    console.log('์•ˆ๋…•');})์ด๋Ÿฐ ์‹์œผ๋กœ.

๊ทธ๋Ÿฐ๋ฐ ๋งŒ์•ฝ this๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธธ ์‹œ! this๋Š” ์–ด๋–ป๊ฒŒ ์ฐพ์•„์•ผ ํ•˜๋‚˜?

const ground = document.querySelector(".ground");

let waiting = false;

function throttle(callback, limit = 200) {
  let waiting = false;

  return function (e) { // ์ด ํ•จ์ˆ˜๊ฐ€ mousemove์— ์˜ํ•ด ์‹คํ–‰๋จ -(2)
  // ์ด ํ•จ์ˆ˜๋Š” ๋ณธ์ธ์ด ๋ˆ„๊ตฌ์— ์˜ํ•ด ์‹คํ–‰๋๋Š”์ง€ ์•Œ๊ณ  ์žˆ์Œ -(3)
  	console.log(this); // ์ด this๋Š” ๋‚˜๋ฅผ ํ˜ธ์ถœํ•œ ๋Œ€์ƒ์ธ ground์ž„ -(4)
    if (!waiting) {
      callback.call(this, e); // ๊ทธ๋ž˜์„œ call ์ด์šฉ -(6)
      waiting = true;

      setTimeout(() => {
        waiting = false;
      }, limit);
    }
  };
}

ground.addEventListener('mousemove', throttle(function() { // throttle์ด ์‹คํ–‰๋จ๊ณผ ๋™์‹œ์— -(1)
// throttle์€ ํ˜ธ์ถœํ•œ ๋Œ€์ƒ์„ ๋ชจ๋ฆ„. ๋ณธ์ธ์ด ์•Œ์•„์„œ ์‹คํ–‰ํ•จ. -(5)
	console.log(this);
    }));

๐Ÿด Debounce

: ์งง์€ ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์œผ๋กœ ์ด๋ฒคํŠธ๊ฐ€ ์—ฐ์†ํ•ด์„œ ๋ฐœ์ƒํ•˜๋ฉด ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋‹ค๊ฐ€ ์ผ์ • ์‹œ๊ฐ„ ๊ฒฝ๊ณผ ํ›„ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๋„๋ก ํ•จ.

const searchInput = document.querySelector('#search-input');
const searchAPI = (query) => {
  // ๊ฒ€์ƒ‰ API ํ˜ธ์ถœ ์ฝ”๋“œ
  console.log(`๊ฒ€์ƒ‰์–ด: ${query}`);
};

const debouncedSearch = debounce(searchAPI, 300); 
// searchAPI ํ•จ์ˆ˜๋ฅผ 300 ๋ฐ€๋ฆฌ์ดˆ ๋™์•ˆ ์ง€์—ฐ์‹œํ‚ด
// ์‚ฌ์šฉ์ž๊ฐ€ 300๋ฐ€๋ฆฌ์ดˆ ์ด๋‚ด์— ๋‹ค๋ฅธ ๋ฌธ์ž ์ž…๋ ฅ -> ์ด์ „ ๊ฒ€์ƒ‰ API ํ˜ธ์ถœ์€ ์ทจ์†Œ๋˜๊ณ 
// ๋งˆ์ง€๋ง‰ ์ž…๋ ฅ ๋ฌธ์ž๋กœ๋งŒ ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰

searchInput.addEventListener('input', (event) => { // ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ํ•จ์ˆ˜ ์‹คํ–‰
  const query = event.target.value;
  debouncedSearch(query);
});