前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库source phase imports 模块导入阶段
JavaScript模块与语言机制

import source 是什么?它和普通 import 有什么不一样?

普通 import 要把模块一路执行完,给你的是导出的值。import source x from "./a.wasm" 只走到「加载并编译好」这一步就停下,给你的是模块的源码对象,对 WebAssembly 来说就是一个还没实例化的 WebAssembly.Module,你可以自己决定怎么实例化、实例化几次。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#模块与语言机制
先看核心答案读代码示例
理解线索

一个模块导入要经过的阶段

  1. 加载和编译取到文件并编译,import source 停在这里
  2. 链接把导入导出接起来,建立实时绑定
  3. 执行运行顶层代码,普通 import 走完这一步才返回

普通 JS 模块目前没有定义源码对象,对 .js 文件写 import source 会直接报错。这不是语法写错了,是宿主还没给 JS 模块提供这一阶段的表示。

核心回答

先记住这个答案

一个模块被 import 时要经过几个阶段:解析地址、加载并编译、链接导入导出、执行顶层代码。普通 import 会一口气走完,给你的是执行后的导出。source phase import 写成 import source mod from "./a.wasm",只走到加载编译完成就停,给你的是这个模块的「源码对象」,还没有链接和执行。目前它主要用于 WebAssembly,拿到的是一个未实例化的 WebAssembly.Module,由你决定用什么导入对象去实例化、实例化几次。

  • import source 获取源码对象
  • 目前的主要用途是导入 WebAssembly 模块
  • import.source() 异步取得源码对象
  • import defer 延迟模块求值

导入一个 WASM 模块

以前要用 WASM,得先 fetch 文件,再调 WebAssembly.compileStreaming 编译,地址还要自己拼。有了 import source,这些交给模块系统。

静态和动态两种写法JavaScript
// 静态写法:拿到的是 WebAssembly.Module,不是实例
import source calcModule from './calc.wasm'

// 可以用不同的导入对象实例化多次
const a = await WebAssembly.instantiate(calcModule, { env: { log: console.log } })
const b = await WebAssembly.instantiate(calcModule, { env: { log: () => {} } })

// 动态写法
const mod = await import.source('./calc.wasm')
console.log(mod instanceof WebAssembly.Module) // true

// 也可以把 Module 发给 Worker,在那边再实例化
worker.postMessage(mod)

Node.js 官方文档把 WASM 的 import source 列在 source phase imports 下,并展示了用同一个 WebAssembly.Module 分别实例化的写法。MDN 仍将这项语法标为实验性,浏览器和运行时支持情况需要按项目目标环境核对;不要把它当成所有环境都能直接运行的写法。 这里的关键区别在于:如果直接 import 一个 WASM 模块(WebAssembly 的 ESM 集成),宿主会替你实例化好,你拿到的是它的导出函数,导入对象也由宿主按模块依赖去找,你插不上手。import source 把实例化的控制权还给了你。

另一个调整求值时机的语法:import defer

import source 是「提前停下」,import defer 是「晚点执行」,两者经常被放在一起讨论。

加载照常,执行推迟到第一次使用
写成 import defer * as heavy from "./heavy.js" 时,heavy.js 和它的依赖照常加载、链接,但顶层代码先不执行,等你第一次读取 heavy 上的某个属性时才同步执行。它只能用命名空间形式,因为要靠「访问属性」来触发执行。 它想解决的是启动性能:有些模块很大,但只在少数分支里用到。动态 import() 也能推迟,但会把调用链全部变成异步;import defer 保持同步写法,只推迟求值成本。这项语法仍属实验性能力,并非所有主流浏览器都支持。实际采用前应核对目标运行环境,不能把它当作已经普遍可用的 import 写法。
回答前,多想一步

容易答错的地方

以为 import source 能用在任何模块上
它要求宿主为这种模块定义了源码对象。WASM 定义了,就是 WebAssembly.Module;普通 JS 模块目前没有,对 .js 文件写 import source,Node.js 会报「这个模块没有定义源码阶段对象」的错误。
把 import defer 当成懒加载
import defer 不推迟下载,文件在页面启动时照样被请求和解析,只是不执行。想连下载一起推迟,还是得用动态 import()。另外如果被推迟的模块里有顶层 await,这部分异步工作没法等到访问时同步完成,会被提前执行。
试着用自己的话回答

面试官还会怎么问?

为什么要把 WASM 的实例化交给开发者?

WASM 模块实例化时需要一个导入对象,里面是它要调用的 JS 函数和内存。同一个模块可能要配不同的导入对象,比如一个实例用于主线程、一个用于测试替身;也可能要把编译好的模块发给多个 Worker 各自实例化,省去重复编译。这些场景都需要拿到「编译好但没实例化」的那个对象。

现在项目里能用这些语法吗?

生产项目里直接写还太早,支持情况在各运行时之间差异很大。Vite 这类工具已经有加载 WASM 的插件和 ?init 这类约定,功能接近。了解这两个提案的价值,主要在于理解模块导入其实分好几个阶段,以及为什么语言要开放这些阶段。

import() 和 import.source() 返回的有什么区别?

import() 返回的 Promise 解决为模块命名空间对象,里面是执行后的导出。import.source() 返回的 Promise 解决为源码对象,没有导出,也没有执行过任何代码。

从一道题,走向一组知识

把知识连起来

模块与语言机制

ES 模块为什么默认就是严格模式?对模块里的函数有什么影响?

模块在链接和执行前还有一道编译,模块代码自动按严格模式编译就是在这一步决定的。

模块与语言机制

哪些操作在非严格模式下悄悄失败,严格模式下却会报错?

这道题讲导入停在哪个阶段,那道题讲模块代码执行时严格模式会把哪些静默错误变成异常。

参考资料

  • JavaScript:模块与语言机制参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 导入一个 WASM 模块
  3. 另一个调整求值时机的语法:import defer
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑