KKUSVERSEJavaScript | JavaScript 기본기 총정리 4편

JavaScriptJavaScript 기본기 총정리 4편
JavaScript 기본기 총정리 4편

기초부터 다시 살펴보는 JavaScript 공부 기록

2025-10-27
9 min

⏱️ 타이머 함수의 최소 지연 시간

setTimeout이나 setInterval의 지연 시간(delay)이 항상 정확하지는 않습니다. 지정한 delay가 4ms 이하인 경우, 최소 지연 시간 4ms가 지정됩니다.

지정한 delay 시간은 콜백 함수를 태스크 큐에 등록하는 시간을 지연시키는 것이며, 실제 실행 시간은 브라우저 성능, CPU 상태, 다른 자바스크립트 코드 실행에 따라 delay보다 길어질 수 있습니다.

🚦 Debounce와 Throttle

Debounce

Debounce는 이벤트가 연속해서 발생해도 마지막 이벤트 이후 일정 시간이 지나야 한 번만 실행되도록 합니다. 입력 필드 자동완성 UI 구현, 버튼 중복 클릭 방지 처리 등에 사용됩니다.

function debounce(callback, delay) {
  let timerId
  // debounce 함수는 timerId를 기억하는 클로저를 반환합니다.
  return (...args) => {
    // 이전 타이머가 남아있으면 취소합니다.
    if (timerId) clearTimeout(timerId)
    // delay가 경과한 후에 콜백을 실행하도록 새로운 타이머를 설정합니다.
    timerId = setTimeout(callback, delay, ...args)
  }
}

Throttle

Throttle은 이벤트가 연속해서 발생해도 일정 시간 간격으로 한 번씩만 실행되도록 합니다. scroll 이벤트 처리나 무한 스크롤 UI 구현 등에 사용됩니다.

function throttle(callback, delay) {
  let timerId
  // throttle 함수는 timerId를 기억하는 클로저를 반환합니다.
  return (...args) => {
    // 타이머가 이미 설정되어 있으면 아무것도 하지 않습니다.
    if (timerId) return
    // delay가 지나면 콜백을 실행하고 타이머를 초기화하여 다음 호출을 허용합니다.
    timerId = setTimeout(() => {
      callback(...args)
      timerId = null
    }, delay)
  }
}

🧠 자바스크립트 엔진 구조

대부분의 자바스크립트 엔진은 크게 2개의 영역으로 구분할 수 있습니다.

콜 스택(Call Stack)

자바스크립트에서 함수를 호출하면 해당 함수의 코드가 평가되어 함수 실행 컨텍스트가 생성됩니다. 생성된 실행 컨텍스트는 실행 컨텍스트 스택(Call Stack) 에 푸시된 뒤 실행되며, 함수 실행이 끝나면 스택에서 팝되어 제거됩니다.

자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택만 가지고 싱글 스레드(Single Thread) 로 동작합니다. 즉, 한 번에 오직 하나의 코드만 실행할 수 있습니다. 이 때문에 네트워크 요청이나 타이머처럼 시간이 오래 걸리는 작업을 메인 스레드에서 동기적으로 처리하면 전체 실행이 블로킹됩니다.

힙(Heap)

힙은 객체가 저장되는 메모리 공간입니다. 콜 스택의 실행 컨텍스트는 힙에 저장된 객체를 참조합니다. 값을 메모리에 저장하려면 먼저 필요한 메모리 공간의 크기를 결정해야 하는데, 객체는 원시 값과 달리 크기가 정해져 있지 않기 때문에 런타임에 메모리 크기가 결정됩니다. 이 때문에 힙은 구조화되어 있지 않은 자유로운 메모리 공간이라는 특징을 갖습니다.

👉 이처럼 콜 스택과 힙으로 구성된 자바스크립트 엔진은 단순히 요청된 작업을 콜 스택을 통해 순차적으로 실행합니다. 비동기 처리에서는 소스 코드의 평가와 실행을 제외한 대부분의 작업을 자바스크립트 엔진을 구동하는 환경, 즉 브라우저나 Node.js가 담당합니다. 예를 들어, 비동기 방식으로 동작하는 setTimeout의 경우, 콜백 함수의 평가와 실행은 자바스크립트 엔진이 수행하지만, 타이머 설정과 콜백 함수 등록은 브라우저나 Node.js가 처리합니다. 이를 위해 브라우저 환경은 태스크 큐이벤트 루프 를 제공합니다.

📬 태스크 큐(Task Queue)

1. 태스크 큐(Task Queue/Event Queue/Callback Queue)

태스크 큐는 setTimeout, setInterval, DOM 이벤트 등 비동기 작업이 완료된 후 실행될 콜백 함수들이 대기하는 큐입니다. 콜 스택이 비어 있으면 이벤트 루프가 큐에서 콜백을 꺼내 실행합니다.

2. 마이크로태스크 큐(Microtask Queue)

마이크로태스크 큐는 태스크 큐보다 우선적으로 처리되는 작은 단위 비동기 작업 큐입니다. 주로 Promise의 .then(), .catch(), .finally()queueMicrotask로 등록된 콜백이 들어갑니다. 콜 스택이 비어 있으면 먼저 마이크로태스크 큐가 처리됩니다.

3. 렌더 큐(Render Queue/Animation Frame Queue)

렌더 큐는 브라우저가 화면을 갱신(Repaint/Render)할 때 실행할 콜백이 대기하는 큐입니다. requestAnimationFrame의 콜백이 들어가며, 이벤트 루프는 마이크로태스크 처리 후, 화면 갱신 시점에 렌더 큐를 실행합니다.

🔄 이벤트 루프(Event Loop)

이벤트 루프는 콜 스택과 큐를 감시하며 비동기 작업을 순차적으로(FIFO) 실행하는 역할을 합니다. 콜 스택이 비어 있으면 먼저 마이크로태스크 큐를 처리하고, 그 다음 태스크 큐의 콜백을 실행합니다. 이를 통해 싱글 스레드 환경에서도 여러 비동기 작업을 효율적으로 처리할 수 있습니다.

🌐 브라우저 내부 구조와 멀티스레드

브라우저에 내장된 자바스크립트 엔진은 싱글 스레드로 동작하지만, 브라우저 자체는 멀티스레드 구조로 동작합니다. 브라우저는 자바스크립트 엔진 외에도 렌더링 엔진과 Web API를 제공합니다.

Web API는 DOM 조작, 타이머 함수, HTTP 요청 등 비동기 작업과 브라우저 전용 기능을 처리합니다. 브라우저는 이러한 작업을 별도의 스레드에서 병렬로 처리할 수 있기 때문에, 메인 스레드에서 자바스크립트 코드가 실행 중이더라도 화면 렌더링, 사용자 입력 처리, 네트워크 요청 등이 동시에 진행될 수 있습니다.

즉, 브라우저는 멀티스레드로 여러 작업을 병렬 처리하며, 자바스크립트 엔진은 싱글 스레드로 코드 실행을 담당하는 구조입니다.


참고 자료

『모던 자바스크립트 Deep Dive』, 이웅모 저, 위키북스