You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ES模块循环依赖生效条件、处理机制及与Node.js require对比咨询

ES模块循环依赖问题解析

近期在项目中收到ESLint关于循环依赖的警告,此前以为ES模块无法实现循环引用,但实际部分场景下可行。下面是两个循环依赖示例:

示例1:带setTimeout的正常运行版本

// ma.mjs
import { b } from "./mb.mjs";

export const a = 1;

export function fa() {
  console.log(b);
}

setTimeout(() => {
  fa();
});

// mb.mjs
import { a } from "./ma.mjs";

export const b = 2;

export function fb() {
  console.log(a);
}

setTimeout(() => {
  fb();
});

// script.mjs (entry point)
import './ma.mjs';

示例2:移除setTimeout的报错版本

// ma.mjs
import { b } from "./mb.mjs";

export const a = 1;

console.log(b);

// mb.mjs
import { a } from "./ma.mjs";

export const b = 2;

console.log(a);

// script.mjs (entry point)
import './ma.mjs';

报错信息:

Uncaught ReferenceError: Cannot access 'a' before initialization

问题解答

1. 循环引用生效需满足什么条件?为何两个示例结果不同?

循环引用能正常运行的核心条件是:不要在模块初始化阶段访问未完成赋值的导出变量。

  • 第一个示例中,setTimeout把变量访问逻辑放到了宏任务队列中。当宏任务执行时,两个模块的顶层代码已经全部执行完毕,a和b都完成了赋值,所以调用函数时能正常获取到对方的变量。
  • 第二个示例直接在模块初始化阶段执行console.log(b)和console.log(a),触发了ES模块初始化的顺序问题:
    1. 入口加载ma.mjs,遇到import { b } from "./mb.mjs",暂停ma的初始化,转而加载mb.mjs。
    2. mb.mjs中遇到import { a } from "./ma.mjs",此时ma已被标记为"正在加载",不会重复加载,继续执行mb的顶层代码:先声明b但未赋值,随即执行console.log(a)——此时ma里的a仅完成了声明(ES模块的import会触发变量声明提升),但还没执行export const a = 1完成赋值,因此抛出初始化前访问变量的错误。

2. ES模块如何处理这种递归场景?

ES模块通过静态分析+命名空间实例化+延迟绑定+初始化顺序控制来处理循环依赖:

  1. 静态分析:代码执行前先扫描所有import/export,构建模块依赖图,确定加载优先级。
  2. 命名空间实例化:为每个模块创建专属命名空间,提前声明所有导出变量(但不赋值),循环引用的模块可互相访问对方的命名空间,但变量处于未初始化状态。
  3. 初始化执行:按依赖图顺序执行模块顶层代码,遇到import就暂停当前模块,先初始化依赖模块;若出现循环依赖,则回到当前模块继续执行,此时对方的变量可能尚未完成赋值。
  4. 实时绑定更新:ES模块的导出是变量的实时引用而非值拷贝,当变量后续完成赋值后,所有引用该变量的地方会自动同步最新值。

ES模块与Node.js CommonJS循环引用机制是否相同?

两者处理机制完全不同:

  • CommonJS是值拷贝:模块加载时执行全部代码,导出的是exports对象的当前状态,循环引用时拿到的是对方exports的半成品,后续对exports的修改不会同步到已引用的变量。
  • ES模块是实时绑定:导出的是变量引用,循环引用时即使初始化阶段访问到未赋值的变量,后续变量赋值后所有引用都会自动更新。此外,CommonJS是动态加载(运行时解析依赖),ES模块是静态加载(编译时解析依赖),这也导致两者循环依赖的处理逻辑有本质区别。

内容的提问来源于stack exchange,提问作者Ardeshir Izadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:40:16