블로그 이름

[JavaScript] setTimeout과 Promise의 실행 순서 및 동작 차이 본문

개발/기타

[JavaScript] setTimeout과 Promise의 실행 순서 및 동작 차이

Hide 2025. 12. 16. 23:32

우선 해당 메서드의 차이점을 비교하게 된 계기는 다음과 같다.

API로 데이터 조회 후 특정 코드가 실행되도록 하려 하였으나, 동기로 동작하도록 수정하는 부분에서 정상 동작하지 않거나 일부 버벅이는 현상이 존재하여 setTimeout과 Promise 중 한 메서드를 사용하여 해당 현상을 해결하고자 하였다.

결과적으로 말하자면 Promise보다 setTimeout이 나중에 실행된다.

 

JavaScript 비동기 처리에서 setTimeout과 Promise는 자주 등장하는 개념으로 실행 순서, 동작 방식, 사용 목적에서 차이가 존재한다.

오늘은 JavaScript 실행 모델(Event Loop), 두 메서드의 내부 동작, 실행 순서 차이 (Microtask vs Macrotask) 를 알아보고자 한다.

 

1. JavaScript가 코드를 실행하는 절차

javaScript는 단일 스레드 (Single Thread) 언어로, 한번에 하나의 작업만 실행할 수 있다. 하지만 브라우저나 Node.js 환경에서 비동기 처리하여 동시에 여러 작업을 처리하는 것처럼 보이게 만든다. 이를 가능하게 하는 핵심 개념이 Event Loop로,

 

Call Stack(호출 스택) - javascript 엔진이 코드를 실행하는 유일한 공간으로, 함수가 호출되면 stack에 쌓이고, 끝나면 제거된다. 그리고 한번에 하나의 함수만 실행 가능하다.

Web APIs / Background 영역 - javascript 엔진 바깥에 존재하며, 브라우저나 Node.js 가 제공하는 기능으로 setTimeout, AJAX, DOM 이벤트 등이 있다. setTimeout을 사용하여 1초 뒤 코드를 실행하게 한다면, javascript에서 해당 코드를 1초 타이머를 등록하도록 요청하며, 실제 시간 측정 및 대기는 Web API 영역에서 처리한다.

Task Queue (Macrotask Queue) - Web API 영역에서 작업이 완료되면 바로 실행되는것이 아닌 Macrotask Queue로 이동한다. setTimeout, setInterval, 이벤트 콜백 등이 대표적이며, Call Stack이 완전히 비어 있을 때에만 Task Queue의 작업이 실행된다. (즉 오래 걸리는 동기 코드가 stack에 있는 경우 setTimeout(0) 이라도 실행이 지연된다.

Microtask Queue - 우선순위가 높은 큐로, Promise.then, catch, finally, queueMicrotask 등이 대표적이다. Call Stack이 비는 즉시 Microtask Queue를 전부 비울 때까지 실행한다. 중간에 다른 Macrotask는 절대 끼어들 수 없다. (Promise가 setTimeout보다 먼저 실행되는 이유)

Event Loop - Call Stack이 비었는지 확인하여, Microtask Queue가 비어 있지 않으면 전부 실행하고 다음 Macrotask Queue에서 하나 실행하는 것을 프로그램이 종료될 때까지 반복한다.

 

간단히 말하자면

동기 코드 우선 실행 -> Microtask를 전부 처리 -> Macrotask 하나 실행 이다.

 

2. setTimeout의 동작방식

setTimeout(() => {
  console.log('setTimeout');
}, 0);


- setTimeout 함수가 call stack 에서 실행된다.

- 타이머가 Web API 영역에서 대기한다

- setTimeout에 지정된 시간이 지나면 Macrotask Queue 로 이동한다.

- Call Stack이 완전히 비었을 때 실행된다

 

3. Promise의 동작방식

Promise.resolve().then(() => {
  console.log('promise');
});


- promise가 즉시 생성되며, then 콜백은 Microtask Queue에 등록된다.

- 실행 중인 Call Stack이 끝나면 즉시 실행된다.

 

아래 예제를 실행해보면 결과는 다음과 같다.

console.log('start');

setTimeout(() => {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(() => {
  console.log('promise');
});

console.log('end');
start
end
promise
setTimeout

- promise (Microtask) 는 setTimeout (Macrotask) 보다 항상 우선 실행된다.

 

Promise는 비동기 작업의 결과를 체계적으로 처리해야 할때, 순차적인 비동기 흐름이 필요할 때 사용한다.

fetch('/api/data')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));


setTimeout은 단순 지연 실행이 필요하거나 UI 렌더링 이후, 이벤트 루프 한 사이클 뒤로 미루고 싶을 때 실행하면 된다.

setTimeout(() => {
  console.log('UI 렌더링 이후 실행');
}, 0);

 

최종 정리

Promise.then은 Microtask Queue로, 가장 먼저 실행되고

setTimeout은 Macrotask로 늦게 실행된다.

 

나같은 경우 ag-grid 라이브러리를 사용하고 있는데, 해당 라이브러리의 UI가 우선 로딩된 후 데이터를 순차적으로 표시하여야 하였는데, API 데이터 조회 속도가 빠르더라도 UI가 로딩되기 전 ag-grid의 옵션을 설정하면 UI 로딩 후 초기화 되는 현상이 존재하여 UI가 로딩된 후 ag-grid의 옵션을 설정해야 하는 상황이었고, setTimeout을 사용하여 UI 렌더링이 끝난 다음 변수에 값을 할당하도록 변경해 주어 해결하였다.

오늘은 Promise와 setTimout의 차이점 및 동작 방식을 알아보았다.