← All issues

Dynamic `import.defer()` semantics

7f06296

JSTests/modules/import-defer-dynamic-evaluation.js

+const ns = await import.defer("./import-defer/eval-tracker.js");
+shouldBe(JSON.stringify(globalThis.deferEvaluations), "[]");
+
+// Symbol 키를 이용한 접근도 evaluation을 유발해서는 안 됩니다.
+shouldBe(ns[Symbol.toStringTag], "Deferred Module");
+shouldBe(JSON.stringify(globalThis.deferEvaluations), "[]");
+
+// Symbol이 아닌 첫 번째 접근에서 모듈이 동기적으로 평가됩니다.
+shouldBe(ns.value, 42);
+shouldBe(JSON.stringify(globalThis.deferEvaluations), JSON.stringify(["eval-tracker"]));
+
+// 이후 import.defer() 호출은 동일한 namespace를 반환하며, 재평가는 발생하지 않습니다.
+const ns2 = await import.defer("./import-defer/eval-tracker.js");
+shouldBe(ns2, ns);

TC39 Deferred Module Evaluation 제안은 모듈 링킹과 모듈 실행을 분리합니다. deferred namespace proxy는 즉시 반환되며, 모듈 본문은 첫 번째 non-Symbol 프로퍼티 접근 시에만 실행됩니다. JSC의 모듈 파이프라인은 엔진 측(graph 탐색, bytecode, microtask 스케줄링)과 WebCore 바인딩 계층(ScriptModuleLoader, JSDOMGlobalObject)으로 나뉘는데, 새로운 "import phase" 파라미터는 두 계층 모두를 거쳐 전달되어야 합니다.

이 commit은 동적 import.defer(specifier) 형식을 구현합니다. 모듈 그래프는 로드 및 링크 단계까지 진행하되, deferred root 자체는 즉시 실행하지 않습니다. GatherAsynchronousTransitiveDependencies()는 실행되지 않은 top-level-await (TLA) 모듈을 post-order로 수집합니다. 수집된 모듈은 두 개의 새로운 내부 microtask(DynamicImportDeferLoadSettled, DynamicImportDeferDependencySettled)를 통해 평가되며, 모든 의존성이 settle되면 반환된 promise가 deferred module namespace로 resolve됩니다.

모든 TLA 의존성 promise를 대기하는 AND-join은 JSPromiseCombinatorsGlobalContext를 shared counter cell로 재사용합니다. Promise.all 내부 구현에서 차용한 패턴이지만, 사양상 핵심 제약이 있습니다. 의존성 promise에 대해 then을 조회해서는 안 됩니다.

import.defer(specifier)
  ├─► load() + link()
  ├─► GatherAsyncTransitiveDeps() → [dep1, dep2, ...]
  ├─► evaluate(depN) ──► AND-join counter (DynamicImportDeferDependencySettled)
  └─► resolve(deferredNamespace)

Namespace proxy dispatch:
  Symbol key  ──► return value  (NO evaluation)
  String key  ──► evaluate() ──► return value

이 변경은 새로운 JS-visible API와 새로운 microtask 유형을 도입하며, promise AND-join과 namespace proxy dispatch 동작 방식이 JSC 모듈 시스템의 모든 계층에 걸쳐 새롭게 추가됩니다. 이 영역은 JS 엔진에서 역사적으로 보안 버그 밀도가 가장 높은 곳에 해당합니다.

🔒

New promise AND-join mechanics, namespace proxy dispatch boundaries, and cross-layer import phase propagation all have audit-worthy angles.

더 확인하려면 구독해 주세요