☁️ goormTIL | JavaScript #19

매루·2025년 9월 30일

goormTIL

목록 보기
17/67
post-thumbnail

📅 2025-09-29

➡️ JavaScript 이벤트 루프에 대해 새롭게 알게 된 것 또는 헷갈리는 부분 정리


🔎 학습 리마인드

📌 프로세스와 쓰레드

💡 프로세스란?

  • 실행 중인 프로그램 → 프로세스
  • 각각 프로세스는 독립된 메모리 공간을 가짐

💡 쓰레드란?

  • 프로세스 안에서 실제로 일이 수행되는 실행 단위
  • 하나의 프로세스는 보통 1개 이상의 쓰레드를 갖고 있음
  • 여러 개의 쓰레드가 있으면 한 프로세스 안에서 동시에 여러 작업 가능 (멀티쓰레드)

💡 자바스크립트는 싱글 쓰레드

  • 자바스크립트 엔진(V8)은 쓰레드가 한 개라서 한 번에 하나의 코드만 실행
  • 동기적 연산이 길어지면 브라우저가 멈춘 것 처럼 보임 (Bloacking)
  • 브라우저(or node.js)가 비동기 환경(Web APIs)을 제공하여 멀티태스킹처럼 보이게 하는 것

📌 Non-blocking I/O

💡 Blocking

  • 현재 흐름을 멈춤 (제어권을 내주고 대기)
    function blockingTask() {
      const start = Date.now();
      while (Date.now() - start < 3000) {
        // 3초 동안 멍하니 기다림
      }
      console.log("블로킹 작업 완료");
    }
    
    console.log("작업 시작");
    blockingTask();
    console.log("작업 완료");
    • 현재 실행 중인 코드가 완료될 때까지 다음 코드의 실행을 멈춤
    • 동기 코드에서 흔히 발생하며, 블로킹 작업이 완료될 때까지 프로그램의 다른 부분이 중단되므로 긴 작업이 있으면 전체 프로그램 성능이 저하될 수 있음

💡 Non-blocking

  • 현재 흐름을 멈추지 않음 (제어권 유지, 다른 일 가능)
    function nonBlockingTask() {
      setTimeout(() => {
        console.log("논블로킹 작업 완료");
      }, 3000);
    }
    
    console.log("작업 시작");
    nonBlockingTask();
    console.log("작업 완료");
    • 다른 코드의 실행을 멈추지 않음
    • 작업이 비동기적으로 처리되어, 긴 작업이 실행되는 동안에도 프로그램의 다른 부분이 계속 실행됨
    • 논블로킹 이벤트 루프를 통해 처리됨

💡 이벤트 루프

  • 브라우저(또는 Node.js)가 비동기 작업을 맡아 처리, 끝난 후 콜백을 올바른 타이밍에 JS엔진으로 전달하도록 조율하는 관리자
    • setTimeout, fetch .. 비동기 코드를 브라우저 Web APIs에 맡김

    • 백그라운드 작업이 끝나면 콜백을 큐에 적재

    • 호출 스택(call stack)이 비는 순간, 이벤트 루프가 큐에서 콜백을 가져와 실행

    • 이 과정을 반복(loop) 함 이것을 Event Loop

💡 Microtask vs Task Queue

  • 이벤트 루프가 스택을 비우면 MicrotaskTask Queue 순으로 처리됨
  • Microtask Queue → Promise.then
  • Task Queue → setTimeout, setInterval, fetch, DOM 이벤트 등
console.log("Start");

setTimeout(() => console.log("timmer (Task)"), 0);

Promise.resolve().then(() => console.log("Promise (Microtask)"));

console.log("end");
// 실행 결과: 시작 → 끝 → 프로미스 → 타이머

자바스크립트 내부 동작을 시각적으로 보여주는 사이트

🔗 https://www.jsv9000.app/

Async + Non-blocking

console.log("시작");

setTimeout(() => {
  console.log("1초 뒤");
}, 1000);

console.log("끝");
// 출력: 시작 → 끝 → (1초 후) 1초 뒤

Sync + Blocking

function heavySyncWork(ms = 2000) {
  const start = Date.now();
  while (Date.now() - start < ms) {} // 바쁜 대기(진짜 멈춤)
}

console.log("A");
heavySyncWork(); // 여기서 UI/입력 모두 멈춤
console.log("B");
// 출력: A → (2초 멈춤) → B

Sync + Non-blocking

// 파일 3개를 동시에 읽고(Non-blocking),
// 모두 끝난 시점에 '순서 있게' 후처리(Sync)
import { readFile } from "node:fs/promises";

async function readAll() {
  const [a, b, c] = await Promise.all([
    readFile("a.txt", "utf8"),
    readFile("b.txt", "utf8"),
    readFile("c.txt", "utf8"),
  ]);
  // 여기부터는 '세 파일 모두 준비된 이후' — 순차 로직 가능
  console.log(a.length, b.length, c.length);
}
readAll();

📌 문서 로드 방식

  • DOMContentLoaded
    • HTML이 모두 파싱 되었을때 실행

    • CSS 이미지 같은 리소스 기다리지 않음

      document.addEventListener("DOMContentLoaded", () => {
        console.log("DOM이 준비되었습니다!");
      });
  • defer 속성 활용
    • DOM 파싱이 끝난 다음에 자동으로 실행 (DOMContentLoaded와 사실상 같은 것)

      <script src="script.js" defer></script>
  • window.onload
    • 모든게 다 로드된 후 실행 (이미지, 스타일 등 모든 리소스가 로드)

      window.onload = () =>{
      	console.log("페이지의 모든 리소스가 로드 된 후 완료"):
      }

0개의 댓글