v156 · comparison · startup cost
Eager vs deferred
The same expensive module, imported two ways. A plain import * as pays its top-level cost the moment the module is imported; import defer * as pays nothing until the first property access — and nothing at all if that access never happens. Run each side and compare the timelines.
import defer…Two imports, two timelines
Eager real
Plain import * as ns from "./expensive.js". Works in every browser.
- nothing yet
Deferred …
import defer * as ns from "./expensive.js".
- nothing yet
Why not just use dynamic import()?
Dynamic import() also defers work, but it defers loading as well as evaluation, so it is asynchronous and usually needs a preload step to avoid a request waterfall — and it forces every caller onto a Promise. import defer keeps the module fetched and parsed during normal graph loading, so the deferred first-use is synchronous: existing synchronous callers do not change. It targets execution cost specifically, not loading.
One caveat from the proposal: a deferred subtree containing top-level await cannot be deferred (property access is synchronous), so those async modules are evaluated eagerly during loading and only the synchronous parts are deferred.