免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

每调用都 new 慢 41 倍、首次构造要 10ms:Intl 格式化到底该不该用的实测复盘

每调用都 new 慢 41 倍、首次构造要 10ms:Intl 格式化到底该不该用的实测复盘 团队里一直流传一句话“Intl 慢能不用就不用。” 我接手过一个表格渲染卡顿的页面性能火焰图直指toLocaleString改完上线后确实快了但同事的总结是“以后数字日期都手写”。直到我在 Node 22 上把Intl.NumberFormat/Intl.DateTimeFormat的成本拆成“构造 / 首次调用 / 复用调用”三步分别计时才发现真正慢的从来不是 Intl 本身而是“每次调用都 new 一个 formatter”这个反模式——它比复用同一个实例慢 41 到 51 倍。这篇文章用 20 万次真实形状的数据把三个成本钉成具体数字并给出一个可落地的判断标准。背景为什么 Intl 被“污名化”开发者的直觉不是没来由的。在渲染几千行表格时把new Intl.NumberFormat(...)写在map里、或反复调用date.toLocaleString(locale, opts)确实会肉眼可见地卡。社区文章也反复强调“构造贵、调用便宜要缓存 formatter”。但“贵”和“便宜”到底差几个数量级很少有人给可复现的数字。结果是两极化要么无脑手写牺牲了 locale、时区、货币符号、紧凑计数compact这些免费正确性要么照抄“缓存”却只在单个组件里缓存列表一多还是重复构造。我用 Node v22.22.2V8 12.xICU 完整数据把成本拆开测想回答三件事第一次构造到底多贵复用调用的单次成本多低每次 new 的反模式究竟慢多少倍数字格式化与日期格式化是否同构解剖成本藏在构造、首次调用、复用调用三步任何一次formatter.format(x)的实际开销都来自三个环节只是权重天差地别构造new Intl.XFormat(locale, opts)要解析 locale、加载 ICU 数据、编译格式化模式。这是一次性、按“localeoptions”维度发生的成本。首次调用在刚构造出的实例上第一次.format()可能触发少量内部惰性初始化通常极小。复用调用此后在同一个实例上反复.format()只做纯格式化最便宜。所以“Intl 慢”的两种真凶都出在环节 1要么在循环里反复触发构造反模式要么在进程冷启动时第一次构造恰好落在首屏关键路径上。环节 3 本身几乎可以忽略。图1把一次格式化拆成“构造 → 首次调用 → 复用调用”。构造是毫秒级的一次性成本复用调用是亚微秒级慢的全部来自反复构造。为拿到真实的“首次构造”数字我特意在全新进程、零预热下测量避免构造函数被 JIT 预热后失真。5 次独立进程取中位Intl.NumberFormat冷构造约 10.0 ms9.5–10.7 msIntl.DateTimeFormat冷构造约 3.5 ms3.3–3.8 ms首次.format()调用约 0.05 ms可忽略实证一数字格式化 20 万次的三写法对比我生成 20 万个互不相同、带两位小数的实数如1234.56分别用三种写法在 Node 22 上跑 5 轮取中位// 写法 A手写en-US 千位分隔 两位小数仅对该 locale 正确 function manualNum(n) { const neg n 0, s Math.abs(n).toFixed(2); const [int, dec] s.split(.); let out , c 0; for (let i int.length - 1; i 0; i--, c) { if (c 0 c % 3 0) out , out; out int[i] out; } return (neg ? - : ) out . dec; } // 写法 B复用同一个 Intl.NumberFormat 实例 const fmt new Intl.NumberFormat(en-US, { minimumFractionDigits: 2, maximumFractionDigits: 2 }); nums.map(n fmt.format(n)); // 写法 C反模式每次调用都 new nums.map(n new Intl.NumberFormat(en-US, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(n));结果每操作纳秒数ns/op20 万次中位写法每操作耗时相对复用手写 A305.9 ns0.71×复用 Intl B430.1 ns1.00×每次 new C17,784 ns41.4×关键结论复用 Intl 只比手写慢 1.41 倍数字格式化几乎打平而反模式 C 比复用慢41.4 倍。反模式多出的 ~17.3 µs/op正是“在已预热进程里每次重新构造”的成本它会随 N 线性放大20 万次累计多出约 3.5 秒。图2数字格式化三种写法的单次成本。横轴为写法纵轴为 ns/op对数刻度反模式 C 与另外两条不在同一量级。实证二日期格式化是否同构日期的情况更极端。我生成 20 万个互不相同的时间戳格式化目标为YYYY-MM-DD HH:mm:ssUTC同样三写法// 写法 A手写 UTC 日期 function manualDate(d) { const p n String(n).padStart(2, 0); return ${d.getUTCFullYear()}-${p(d.getUTCMonth()1)}-${p(d.getUTCDate())} ${p(d.getUTCHours())}:${p(d.getUTCMinutes())}:${p(d.getUTCSeconds())}; } // 写法 B复用单个 DateTimeFormat const df new Intl.DateTimeFormat(en-US, { timeZone: UTC, year:numeric, month:2-digit, day:2-digit, hour:2-digit, minute:2-digit, second:2-digit, hour12:false }); dates.map(d df.format(d)); // 写法 C反模式每次 new dates.map(d new Intl.DateTimeFormat(en-US, { timeZone:UTC, /* 同上 */ }).format(d));结果ns/op20 万次中位写法每操作耗时相对复用手写 A151.8 ns0.16×复用 Intl B932.7 ns1.00×每次 new C47,389 ns50.8×日期复用比手写慢6.14 倍绝对值仍仅 0.93 µs/op极快但反模式 C 比复用慢50.8 倍。结构完全同构慢的永远是“反复构造”不是format本身。图3日期格式化三种写法。复用 Intl 虽比手写慢 6 倍但单次仍不足 1 微秒且免费获得时区与 locale 正确性。局限手写不是银弹冷构造也有代价把证据摆全边界要讲清楚手写只对“你写死的那个 locale”正确。换de-DE千位用.、小数用,、加货币符号位置、compact 计数1.3M、序数1st/2nd或本地化时区手写要么重写要么直接错。Intl 一次构造后对所有 locale 免费正确。冷构造的 10ms 真的会痛。若页面首屏关键路径上第一次格式化才构造 formatter这 10ms 直接进首屏耗时。解法不是“禁用 Intl”而是把构造提到模块作用域 / 用Map按localeoptions记忆化让它在非关键时机完成一次。盈亏平衡点是判断该不该手写的标尺。以本机数据估算数字格式化约 576 次、日期约 75 次之后复用写法的总耗时就低于“每次 new”的反模式。也就是说——列表、表格、循环、批量导出一律复用到底只有“整页就格式化一个值”且对 locale 没要求时手写才划算。结论与下一步一句话方法论Intl 的代价 99% 在“构造”把 formatter 提到模块级或按localeoptions记忆化复用就能同时拿到性能与国际化正确性唯一该手写的场景是“单点、无 locale 诉求、且处于极致热路径”。别再用“Intl 慢”一刀切禁用它也别在循环里new Intl.XFormat。可复现命令Node 22node -e const tprocess.hrtime.bigint(); new Intl.NumberFormat(en-US); console.log(cold construct ms:, Number(process.hrtime.bigint()-t)/1e6); 开源地址矩阵门户GitHub - wangzifan396-wzf/WB: nano-tools: 1310 single-file, zero-dependency, local-first web utilities in one portal. Offline and private, nothing leaves your browser. Binary protocol parsers, crypto, dev, audio, visualization, productivity. · GitHub单文件工具聚合器GitHub - wangzifan396-wzf/nano-workbench: Single-file tabbed launcher for the nano-tools matrix - one tab, 382 curated tools (of 1310), instant switching. Zero-dep. Part of nano-tools. · GitHubGitHub 组织主页wangzifan396-wzf (WangZi) · GitHub
返回列表