JavaScript의 모듈 시스템은 크게 CommonJS(require)와 ESM(import) 방식으로 나뉩니다. 이 두 방식의 핵심적인 차이점 중 하나는 모듈 로딩 방식이며, require()
는 동기적(Synchronous)이고, import
는 비동기적(Asynchronous)으로 동작합니다.
이번 글에서는 두 방식의 실행 모델을 심층적으로 분석하여, 왜 require()는 동기적이고 import는 비동기적인지를 설명하겠습니다.
CommonJS의 require()
는 호출 시점에서 해당 모듈을 즉시 로드하고 평가를 완료할 때까지 실행을 블로킹합니다. 따라서 코드 실행 흐름을 멈추고 모듈의 모든 내용을 읽고 실행한 후에야 다음 코드가 실행됩니다.
console.log("Before require");
const message = require("./module.js"); // <- 파일을 읽고 실행이 끝날 때까지 대기 (Blocking)
console.log("After require");
Before require
(module.js 실행 내용)
After require
✅ "Before require"
가 출력된 후, require("./module.js")
가 실행됩니다.
✅ module.js
의 로딩과 실행이 완료될 때까지 블로킹되며, 그 이후 "After require"
가 출력됩니다.
📌 require()는 동기적 실행 모델을 따르며, 모듈 로드가 완료될 때까지 실행 흐름을 멈춘다.
ESM(ECMAScript Modules)의 import
는 비동기적으로 실행되며, 모듈을 병렬로 가져옵니다. 즉, import
는 블로킹 없이 모듈을 로드하고, 이후 실행 흐름을 유지하면서 로드 완료 후 평가됩니다.
console.log("Before import");
import("./module.js").then(() => {
console.log("Module loaded");
});
console.log("After import");
Before import
After import
(module.js 실행 내용)
Module loaded
✅ "Before import"
가 출력됨
✅ import("./module.js")
는 비동기적으로 실행되므로 즉시 다음 코드("After import")가 실행됨
✅ module.js
가 로드된 후 "Module loaded"
가 출력됨
📌 import는 실행 흐름을 블로킹하지 않고, 모듈을 병렬로 가져오면서 필요할 때 평가된다.
비교 항목 | CommonJS (require() ) | ESM (import ) |
---|---|---|
실행 방식 | 동기적 (Blocking) | 비동기적 (Non-blocking) |
모듈 로딩 시점 | 즉시 로드 | 필요할 때 로드 가능 (지연 로딩) |
브라우저 지원 | ❌ (Node.js 전용) | ✅ (브라우저 네이티브 지원) |
Vite에서 사용 | ❌ 느리므로 비효율적 | ✅ 빠른 로딩 가능 |
✅ Vite가 ESM을 활용하는 이유
Vite는 require()
처럼 모든 파일을 한 번에 로드하는 방식이 아니라, 브라우저의 ESM 기능을 활용하여 필요한 모듈만 비동기적으로 가져오기 때문에 빠른 개발 환경을 제공한다. 🚀
require()
는 동기적(Synchronous) 실행 모델을 따르며, 모듈이 로드될 때까지 실행 흐름을 멈춘다.import
는 비동기적(Asynchronous) 실행 모델을 따르며, 모듈이 로드되는 동안 다른 코드가 실행될 수 있다.고급 개발자로서 효율적인 모듈 로딩을 고려할 때, 어떤 환경에서 어떤 모듈 시스템을 사용할지 깊이 이해하는 것이 필수적입니다. 😊