렌더링은 브라우저의 결정이며, JavaScript의 결정이 아니다

발행: (2026년 5월 1일 AM 02:37 GMT+9)
10 분 소요
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the full text of the post (the paragraphs you’d like translated). Could you please paste the article’s content here? I’ll keep the source line and all formatting exactly as you’ve requested.

Source: https://dev.to/marshateo/javascript-event-loop-series-building-the-event-loop-mental-model-from-experiments-4d8i

개요

이 글은 JavaScript가 실제로 어떻게 실행되는지에 대한 시리즈의 다섯 번째 기사입니다. 전체 시리즈는 여기 또는 제 **웹사이트**에서 읽을 수 있습니다.

DOM을 변경합니다.
화면이 업데이트되기를 기대합니다.
그렇지 않습니다.

왜일까요?

이전 기사들에서 우리는 세 가지 제약을 설정했습니다:

  1. JavaScript는 작업을 끝까지 실행합니다.
  2. 작업은 스케줄링 경계를 형성합니다.
  3. 마이크로태스크는 다음 단계로 넘어가기 전에 완전히 소진되어야 합니다.

이제 네 번째 제약을 추가합니다:

브라우저는 매크로태스크가 실행되는 동안이나 마이크로태스크가 소진되는 동안 렌더링을 하지 않습니다.

렌더링은 브라우저의 결정

Up to this point we’ve focused on two pieces of the system:

  • The JavaScript engine – executes code and manages the call stack.
    JavaScript 엔진 – 코드를 실행하고 호출 스택을 관리합니다.
  • The runtime – provides the event loop and scheduling rules.
    런타임 – 이벤트 루프와 스케줄링 규칙을 제공합니다.

Neither of these is responsible for rendering. Beyond them, the browser also contains a rendering engine – the subsystem that performs layout and painting.

  • The engine executes your code.
    • 엔진은 코드를 실행합니다.
  • The runtime decides when that code runs.
    • 런타임은 그 코드가 언제 실행될지를 결정합니다.
  • The rendering engine decides when the result becomes visible.
    • 렌더링 엔진은 결과가 언제 보이게 될지를 결정합니다.

For simplicity, this article will refer to that rendering engine simply as the browser.
간단히 말해, 이 글에서는 해당 렌더링 엔진을 브라우저라고 부르겠습니다.

렌더링 오해

제가 처음 JavaScript를 배우기 시작했을 때, 몇 가지 합리적으로 보이는 사고 모델을 가지고 있었습니다:

  • DOM 업데이트는 즉시 렌더링됩니다.
  • UI를 변경하면 사용자가 즉시 볼 수 있습니다.
  • 브라우저는 초당 60 fps로 지속적으로 렌더링합니다.

이러한 생각은 화면이 자주 빠르게 업데이트되기 때문에 자연스럽게 느껴지지만, 완전하지는 않습니다. 렌더링은 DOM이 변경될 때마다 발생하지 않습니다. 대신, **“안전한 기회”**가 있을 때만 발생합니다 — 현재 매크로태스크가 끝나고 마이크로태스크 큐가 비어 있을 때.

렌더링은 DOM 변형에 의해 트리거되는 것이 아니라, 스케줄링 경계에 의해 제어됩니다. 이를 테스트해 봅시다.

실험 실행

이 실험들은 브라우저의 렌더링 동작에 의존합니다.

  1. 다음 내용을 가진 간단한 HTML 파일을 만듭니다:

    Initial
    Enter fullscreen mode
    Exit fullscreen mode
  2. 브라우저에서 파일을 엽니다.

  3. 이 시리즈의 모든 코드 스니펫은 브라우저 콘솔에 붙여넣어 실행할 수 있습니다.

Note: 이 예제들은 DOM 및 브라우저 렌더링에 의존하기 때문에 Node.js에서는 동작하지 않습니다.

Test 1: 하나의 매크로태스크 내부에서 DOM 업데이트

같은 매크로태스크 안에 여러 DOM 업데이트가 있을 때 어떤 일이 일어날까요? 최종 문자열이 준비되기 전에 자리표시자를 사용하는 코드를 살펴보세요:

const box = document.getElementById("box");

box.textContent = "Temporary string";

for (let i = 0; i  {
  box.textContent = "Final string of Test 2";
});

다시, 우리는 **“Final string of Test 2”**만 보게 됩니다.

초기 매크로태스크가 실행되어 **“Temporary string.”**을 설정합니다. 호출 스택이 비워진 후 마이크로태스크가 즉시 실행되어 DOM을 **“Final string.”**으로 업데이트합니다. 이제야 브라우저가 렌더링할 기회를 얻습니다.
마이크로태스크는 동기 코드와 마찬가지로 렌더링을 지연시킵니다.

Test 3: 새로운 태스크로 나누면 페인트가 허용됩니다

이제 타이머 콜백을 살펴보세요:

const box = document.getElementById("box");

box.textContent = "Temporary string";

setTimeout(() => {
  box.textContent = "Final string of Test 3";
}, 1000);

이번에는 **“Temporary string,”**이 보이고 1초 후에 **“Final string of Test 3”**이 나타날 수 있습니다.

우리는 태스크 경계를 도입했습니다. 브라우저는 초기 매크로태스크를 마치고 마이크로태스크를 소진한 뒤(여기서는 없음) 렌더링 기회를 얻습니다. 렌더링을 선택하면 **“Temporary string”**이 표시됩니다. 이후 타이머의 매크로태스크가 실행될 때 DOM이 **“Final string,”**으로 업데이트되고 다음 렌더링에 반영됩니다.

렌더링은 태스크 경계에서 허용됩니다. 이는 매크로태스크 사이에 렌더링이 보장된다는 의미가 아니라, 그곳에서 발생할 수 있다는 의미입니다.

Why Rendering Waits

If the browser could render in the middle of a macrotask or while microtasks are draining, it could display a half‑updated DOM, inconsistent layout, or partially computed state.

With the constraint that rendering only occurs after a macrotask finishes and the microtask queue is empty, the browser renders only stable states. No partial work is in progress, so rendering is atomic with respect to JavaScript execution.

올바른 정신 모델

실험을 통해 브라우저가 DOM이 변경될 때마다 렌더링하지 않는다는 것을 보여주었습니다. 대신:

브라우저는 JavaScript가 자신의 턴을 마친 후에만 렌더링합니다.

“턴”이란:

  1. 현재 매크로태스크가 완료되고, 그리고
  2. 마이크로태스크 큐가 완전히 비워지는 것을 의미합니다.

렌더링은 이러한 경계에서만 허용됩니다. 이는 브라우저가 매 턴마다 렌더링한다는 의미가 아니라, 턴 중에는 렌더링할 수 없다는 뜻입니다. 렌더링 결정은 시리즈 전반에 걸쳐 구축해 온 동일한 스케줄링 규칙에 의해 제한됩니다.

이 시리즈

다음에 대비하는 내용

렌더링이 특정 경계에서만 발생한다면 새로운 질문이 떠오릅니다: 올바른 순간에 실행되는 코드를 어떻게 작성할까요?

setTimeout은 새로운 매크로태스크를 생성하지만 브라우저의 프레임 타이밍과 일치하지 않습니다.
마이크로태스크는 렌더링을 지연시키지만 렌더링 자체를 스케줄하지는 못합니다. 부드러운 애니메이션과 반응형 업데이트를 원한다면 브라우저가 다음 프레임을 렌더링하기 직전에 코드를 실행할 방법이 필요합니다.

이것이 requestAnimationFrame이 설계된 목적입니다. 다음 글에서는 브라우저의 렌더링 사이클이 어떻게 동작하는지, 그리고 그와 조화롭게 작업을 스케줄링하는 방법을 자세히 살펴보겠습니다.

이 글은 원래 제 웹사이트에서 게시되었습니다.

0 조회
Back to Blog

관련 글

더 보기 »