☰
Node.js 性能实践 7.2:优先使用原生 JS 方法,替代 Lodash 等用户空间工具库
2026/10/1 8:13:06 网站建设 项目流程
  • 文档
  • 教程
  • 后端

【免费下载链接】nodebestpractices

✅ The Node.js best practices list (July 2026)

项目地址:https://gitcode.com/GitHub_Trending/no/nodebestpractices
点击查看免费下载

导读

本文对应 nodebestpractices 仓库「性能实践」章节的第 7.2 条(原文档,本仓库同时提供 Basque 语版本)。它回答一个高频问题:当 V8 引擎与现代 ECMAScript 标准已经把大量数组/字符串/对象操作内置化之后,你的项目是否还需要 Lodash、Underscore 这类工具库?读完本文,你将掌握:原生方法与工具库之间的真实性能差距、如何用benchmark编写可复现的对比测试、如何用 ESLint 插件自动揪出"可以不用却用了"的工具库调用,从而减少依赖、提升运行时性能。


一、核心结论:为什么原生方法往往更优

在Array.concat、Array.fill、Array.filter、Array.map、(Array|String).indexOf、Object.find等常用操作上,使用原生方法而不是lodash或underscore通常更划算。原因有两方面:

  • 性能损耗:工具库在大多数操作上并不比 V8 内置实现快,反而可能因为额外的函数包装、参数归一化和特性兼容逻辑而引入不必要的开销;
  • 体积与依赖成本:每引入一个工具库就多一个依赖项,增大安装体积与维护面;很多场景下你只是用了其中一两个方法,却要背负整个库。

仓库 README 第 7.2 节(README.md)给出了高度凝练的 TL;DR 版本,与本文原文档互为印证:

TL;DR:It's often more penalising to use utility libraries likelodashandunderscoreover native methods as it leads to unneeded dependencies and slower performance. Bear in mind that with the introduction of the new V8 engine alongside the new ES standards, native methods were improved in such a way that it's now about 50% more performant than utility libraries.

也就是说:随着新 V8 引擎与新 ES 标准的引入,原生方法已被大幅优化,整体上比工具库大约高出50%的性能;而"否则"的代价是——你不得不维护一个性能更差、依赖更多的项目,而原本几行原生代码就能解决的事,却要引入整个文件。


二、性能证据:Lodash 与 V8 原生方法的基准对比

原文档引用的基准测试对多种 Lodash 方法进行了对比。下图展示了这些测试结果的平均值:Lodash 方法完成相同任务平均要比 V8 原生方法多花 146.23% 的时间。

这张图直观地说明:性能差距不是个别方法的偶发现象,而是工具库在同类操作上的普遍性代价。结论背后的逻辑链条很清晰——既然 V8 引擎把Array、String等内置方法优化到了接近 JIT 极限的程度,任何"再包一层"的第三方实现都很难超越它,反而常常垫底。


三、亲手复现:用 benchmark 编写concat对比测试

原文档给出了一个可直接运行的基准测试脚本,对_.concat(lodash)、__.concat(underscore)与原生Array.concat三方进行对比:

const _ = require("lodash"); const __ = require("underscore"); const Suite = require("benchmark").Suite; const opts = require("./utils"); // 公共测试选项,如迭代次数、延迟等 const concatSuite = new Suite("concat", opts); const array = [0, 1, 2]; concatSuite .add("lodash", () => _.concat(array, 3, 4, 5)) .add("underscore", () => __.concat(array, 3, 4, 5)) .add("native", () => array.concat(3, 4, 5)) .run({ async: true });

要点说明:

  • 依赖benchmark库(require("benchmark").Suite)来构建和运行基准套件;
  • 三个用例共享同一个输入数组[0, 1, 2],追加同样的参数3, 4, 5,保证比较公平;
  • run({ async: true })表示异步运行,避免长时间同步测试阻塞进程;
  • 公共选项(如采样次数)集中放在./utils模块中,便于在所有套件间保持一致。

运行后得到类似下面的输出(每个用例会展示 ops/sec 与统计误差,误差越小说明结果越可信):

从输出可以看到,原生array.concat(3, 4, 5)的吞吐量显著高于 lodash 与 underscore 版本——这正是第 2 节 146.23% 差距在单个方法上的具体体现。你也可以把同样的套路扩展到fill、filter、map、indexOf、find等方法,逐一验证自己项目中最常用的操作,用数据而非直觉决定是否移除某个工具库。

提示:本文只摘录了concat这一最直观的示例;原文档还提供了更长的基准清单与可运行的彩色版脚本(index.js),你可以按同样思路在本仓库的 sections/performance 目录下组织自己的实验脚本,思路完全一致。


四、理念背书:"You don't (may not) need Lodash/Underscore"

原文档引用了一段广为人知的论述,值得完整保留:

Lodash 和 Underscore 是优秀的现代 JavaScript 工具库,在前端开发者中被广泛使用。然而,当你的目标是现代浏览器时,你会发现得益于 ECMAScript5(ES5)和 ECMAScript2015(ES6),许多方法已经被原生支持。如果你希望项目拥有更少的依赖,并且清楚自己的目标运行环境,那么你可能并不需要 Lodash/Underscore。

这段引述给出了两个关键判断前提,也是本文所有建议的适用范围:

  1. 目标环境较新:只有当你确定运行环境(Node 版本 / 浏览器版本)已内置相应 ES5/ES6 方法时,"原生替换"才是安全的;
  2. 依赖最小化诉求:如果你的项目对依赖数量和包体体积敏感(例如追求更快的npm install、更小的部署产物),原生方法是明确更优的选择。

换言之,这不是"工具库无用论",而是"在满足环境前提下,优先使用平台已提供的能力"。


五、落地工具:用 ESLint 自动检测"不必要"的工具库用法

理念与基准都有了,剩下的问题是如何在团队代码库中持续执行。原文档推荐使用 ESLint 插件eslint-plugin-you-dont-need-lodash-underscore,它能在你使用工具库但完全可以用原生方法替代时给出警告与建议。

5.1 配置方式

在 ESLint 配置文件中加入该插件的推荐预设即可:

{ "extends": ["plugin:you-dont-need-lodash-underscore/compatible"] }
  • compatible预设面向那些仍然兼容原生方法语义的规则,适合逐步迁移的存量代码库;
  • 插件同样支持针对 lodash 与 underscore 的独立规则集,可按需开启。

5.2 实际效果示例

考虑下面这段代码:

const _ = require("lodash"); // ESLint 会对下面这一行给出建议标记 console.log(_.map([0, 1, 2, 4, 8, 16], (x) => `d${x}`));

_.map的用法与原生Array.prototype.map完全等价,因此 ESLint 会在这一行标注提示,建议你改用[0, 1, 2, 4, 8, 16].map(...)。下图展示了启用 YDNLU(You Don't Need Lodash/Underscore)插件后 ESLint 的实际输出:

原文档也坦诚地指出:这个例子相对简单,现实代码库中的用法通常更复杂(例如涉及 lodash 特有的_.chain、深层路径访问等原生没有直接对应的能力),但示例足以说明插件的工作机制——它能区分"原生可替代"与"必须用库"两种情况,把前者标记出来供你决策。

5.3 迁移建议

结合本仓库 性能实践章节 的整体思路,可以按以下顺序落地:

  1. 先在 ESLint 中启用compatible预设,让存量代码暴露所有"可原生替换"的点位;
  2. 对告警逐条人工复核,确认目标运行环境确实支持对应原生方法(尤其注意Array.prototype.fill、String.prototype.includes等对 Node 版本有要求的 API);
  3. 对确认安全的调用改为原生写法,并跑通测试(本仓库 testingandquality 章节强调的测试体系可用来兜底行为一致性);
  4. 观察改动前后的基准数据与包体积变化,量化收益。

六、结论与适用范围

本文结论:在新版本 V8/Node.js 环境下,Array、String与Object上的常见操作应优先使用原生方法;工具库只有在原生确实缺失能力(或团队明确需要其 API 风格)时才值得引入。这样做的收益是双重且可量化的——运行时性能提升(整体约 50% 的量级)与依赖面收缩。

适用范围与前提:

  • 依赖 Node 运行时,原生方法性能以 V8 引擎实现为准;文中 50% 与 146.23% 均为原文档引用的基准测试数据,实际收益会随方法、数据规模与引擎版本波动,建议用第三节的 benchmark 脚本在自己的环境复测;
  • 涉及旧版本运行时或需要兼容旧浏览器时,应保留工具库或使用 polyfill,切勿盲目替换;
  • 该实践属于本仓库 sections/performance 性能章节的一部分,与同章节"不要阻塞事件循环"(block-loop.md)等条目共同构成 Node.js 性能优化的完整拼图。

延伸阅读:仓库根目录 README.md 提供了本条实践的 TL;DR 摘要,中文版 README 亦收录了同义表述,可对照阅读;若需要其他语言的对应文档,本仓库在 sections/performance 下维护了 basque、brazilian-portuguese、french、japanese、polish、russian 等多个翻译版本(如 nativeoverutil.basque.md、nativeoverutil.polish.md)。

  • 文档
  • 教程
  • 后端

【免费下载链接】nodebestpractices

✅ The Node.js best practices list (July 2026)

项目地址:https://gitcode.com/GitHub_Trending/no/nodebestpractices
点击查看免费下载

相关推荐

上一篇:ai-memory 作用域标记文件 `.ai-memory.toml` 完全指南:workspace/project 声明、捕获排除与 Allowlist 模式
下一篇:GxEPD2库版本升级与迁移指南:从1.x到最新版的关键变化

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询