哪种时间格式化 API 的性能最好,原生 API 性能一定好于第三方库吗
发现问题
在项目中有一个需求,需要绘制 CPU 占用和时间关系的 line chart ,数据量在几万到几十万级别。由于后台返回的是时间戳,需要在前端进行格式化。在前端进行时间格式化,下面几种都是常用的 API :
// 使用 moment 第三方库
moment(new Date()).format("hh::mm");
// 使用 getHours + getMinutes
let now = new Date();
[now.getHours(), now.getMinutes()].join(":");
// 使用 toLocaleString
new Date().toLocaleString('zh-CN', {
hour: "numeric",
minute: "numeric",
hour12: false
});
// 使用 Intl.DateTimeFormat
Intl.DateTimeFormat('zh-CN', {
hour: "numeric",
minute: "numeric",
hour12: false
}).format(new Date());
本人在查阅 MDN 文档对 toLocaleTimeString
介绍的时候看到,Intl.DateTimeFormat
API 的性能较好,因此项目中使用 Intl.DateTimeFormat
进行格式化。
在实际测试的时候,line chart 渲染出现较长时间(5 秒以上)卡顿的情况,还阻塞了同一页面上 pie chart 的渲染(这没多少数据,原本应该很快的)。
在对比同事使用 moment
格式化的 line chart 时,同事的数据量没有本人的大,但是可以明显感觉到性能要好。因此本人也改用了 moment
进行尝试,结果性能提升明显。
对比测试
事后本人对 API 的性能感到非常好奇,moment
究竟比 Intl.DateTimeFormat
快多少。因此本人把常用的 API 都进行了测试,代码如下:
const moment = require("moment");
let base = +new Date(1968, 9, 3);
let oneDay = 24 * 3600 * 1000;
console.time("moment");
for (let i = 1; i < 20000; i++) {
let now = new Date(base += oneDay);
moment(now).format("hh:mm");
}
console.timeEnd("moment");
console.time("getHours and getMinutes");
for (let i = 1; i < 20000; i++) {
let now = new Date(base += oneDay);
[now.getHours(), now.getMinutes()].join(":");
}
console.timeEnd("getHours and getMinutes");
console.time("Date.prototype.toLocaleString");
for (let i = 1; i < 20000; i++) {
let now = new Date(base += oneDay);
now.toLocaleString('zh-CN', {
hour: "numeric",
minute: "numeric",
hour12: false
})
}
console.timeEnd("Date.prototype.toLocaleString");
console.time("Intl.DateTimeFormat");
for (let i = 1; i < 20000; i++) {
let now = new Date(base += oneDay);
Intl.DateTimeFormat('zh-CN', {
hour: "numeric",
minute: "numeric",
hour12: false
}).format(now);
}
console.timeEnd("Intl.DateTimeFormat");
大家也可以复制上面的代码自己跑一下,需要安装 moment
依赖。
本人这边给大家公布一下结果:
结果有点出乎意料,格式化两万个时间,moment
仅仅耗时 77.15ms
,但是 Intl.DateTimeFormat
却花了 3.574s
,性能差距近 50 倍。还有一个 Date.prototype.toLocaleString
更夸张了,花了 3.863s
,反倒是 getHours
和 getMinutes
性能最好,只需要 12.141ms
,相比 Intl.DateTimeFormat
性能提升近 300 倍。
那么格式化 20 万个时间性能如何呢?
从结果上看,moment
以及 getHours
和 getMinutes
性能依旧出色,循环次数增加 10 倍,耗时大约只增加了 5 倍,时间复杂度约为 O(logn)
。Date.prototype.toLocaleString
耗时 37.536s
,可以看出时间成线性增长,时间复杂度 O(n)
。而 Intl.DateTimeFormat
有点夸张,不仅比 Date.prototype.toLocaleString
更慢了,而且花了 40.308s
,远高于线性的 35.74s
,时间复杂度高于 O(n)
。
总结
- 原生 API 性能不一定比第三方库好;
- 在格式化大量时间时推荐使用
moment
或者getHours
和getMinutes
,不要使用Date.prototype.toLocaleString
和Intl.DateTimeFormat
,不仅性能很烂,配置项也很难用;