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

为何ESM实例创建速度慢于CJS?Node.js实测对比

为什么CommonJS创建实例的速度远快于ES模块?

我编写了两段逻辑几乎一致的代码,分别采用ES模块(.mjs)和CommonJS(.js)格式,测试大量创建实例的性能差异,结果发现CommonJS的速度显著快于ES模块。

测试代码

1. a.mjs (ESM)

function Worker(health) {
  this._health = health ?? 10;
}

function JuniorEngineer(health, intelligence) {
  this._super(health);
  this._intelligence = intelligence ?? 1;
  this._isBornGenius = intelligence > 10;
}

Worker.prototype.work = function () {
  this._health--;
};

Worker.prototype.getHealth = function () {
  return this._health;
};

JuniorEngineer.prototype = Object.create(Worker.prototype, {});

JuniorEngineer.prototype._super = function (health) {
  return Worker.call(this, health);
};

JuniorEngineer.prototype.getIntelligence = function () {
  return this._intelligence;
};

JuniorEngineer.prototype.work = function () {
  Worker.prototype.work.call(this);
  this._intelligence++;
};

JuniorEngineer.prototype.isBornGenius = function () {
  return this._isBornGenius;
};

function main() {
  var startTime = performance.now();
  console.time();
  const amount = 10000000;
  for (var i = 0; i < amount; i++) {
    const junior = new JuniorEngineer(10, Math.floor(Math.random() * 20));
    junior._isBornGenius;
  }
  var endTime = performance.now();
  console.timeEnd();
}

main();

export { Worker, JuniorEngineer };

2. a.js (CJS)

function Worker(health) {
  this._health = health ?? 10;
}

function JuniorEngineer(health, intelligence) {
  this._super(health);
  this._intelligence = intelligence ?? 1;
  this._isBornGenius = intelligence > 10;
}

Worker.prototype.work = function () {
  this._health--;
};

Worker.prototype.getHealth = function () {
  return this._health;
};

JuniorEngineer.prototype = Object.create(Worker.prototype, {});

JuniorEngineer.prototype._super = function (health) {
  return Worker.call(this, health);
};

JuniorEngineer.prototype.getIntelligence = function () {
  return this._intelligence;
};

JuniorEngineer.prototype.work = function () {
  Worker.prototype.work.call(this);
  this._intelligence++;
};

JuniorEngineer.prototype.isBornGenius = function () {
  return this._isBornGenius;
};

function main() {
  var startTime = performance.now();
  console.time();
  const amount = 10000000;
  for (var i = 0; i < amount; i++) {
    new JuniorEngineer(10, Math.floor(Math.random() * 20)).isBornGenius();
  }
  var endTime = performance.now();
  console.timeEnd();
}

main();

module.exports = { Worker, JuniorEngineer };

测试结果

  • ESM:145.3415ms
  • CJS:59.676541ms

性能差异的核心原因

1. 严格模式的默认启用

ES模块默认强制开启严格模式,而CommonJS默认不启用(除非手动声明'use strict')。严格模式下V8引擎的部分优化会受到限制:

  • 严格模式禁止this指向全局对象,构造函数执行时的this绑定逻辑更复杂,增加了引擎的处理开销。
  • 严格模式下对变量、属性的访问检查更严格,会打断V8的内联优化和隐藏类(Hidden Class)优化路径。

2. V8引擎的优化优先级与成熟度

Node.js对CommonJS的优化迭代时间更长,V8引擎对CJS模块中的函数、构造函数的优化支持更完善:

  • CJS模块的函数处于函数作用域,V8更容易将其标记为可优化的函数类型,比如进行内联优化、隐藏类的稳定化处理。
  • ES模块的词法作用域特性,导致V8在处理模块内的构造函数时,需要额外处理作用域链,增加了运行时开销。

3. 模块加载与执行的底层差异

虽然测试核心是实例创建而非模块加载,但ESM的延迟解析(lazy parsing)机制会影响首次执行时的函数编译:

  • ESM采用静态解析,会先进行模块依赖分析再编译执行,而CJS是加载时立即编译执行,构造函数的编译时机更早,引擎有更多时间进行预优化。

4. 测试代码的细微差异(次要因素)

ESM测试中直接访问实例属性junior._isBornGenius,而CJS中调用isBornGenius()方法。不过这个差异对性能的影响远小于前面的核心因素,统一测试逻辑后(比如两者都调用方法或都直接访问属性),耗时差距依然存在,只是略有缩小。

验证建议

  • 在CJS文件顶部添加'use strict',会发现其性能接近ESM的耗时,验证严格模式的影响。
  • 调整测试循环中的操作,统一属性访问方式,排除测试逻辑的干扰。

内容的提问来源于stack exchange,提问作者CHOI GIHOAWN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 15:17:07