问题诊断
首先,大家来看下这段代码
js
function TimeDisplay() {
const time = new Date().toLocaleTimeString();
return <div>{time}</div>;
}
是不是看着很简单,很眼熟,很常见,但是这段代码每次渲染都会创建new Date()
实例 ➔ 执行toLocaleTimeString()
➔ 触发垃圾回收,在高频更新场景下会产生不必要的性能损耗
优化方案
1. 静态时间展示(只需初始值)
js
const [time] = useState(() => new Date().toLocaleTimeString()); // 初始化只执行一次
return <div>{time}</div>;
- 优点:彻底避免重复实例化,且无副作用
- 局限:时间不能自动更新
- 适用场景:展示固定时间
2. useRef固定值
js
const timeRef = useRef(new Date().toLocaleTimeString());
return <div>{timeRef.current}</div>;
- 优点:避免重复实例化;内存占用稳定
- 局限:时间永不更新
- 适用场景:静态时间快照
3. useMemo空依赖缓存
js
const time = useMemo(() => new Date().toLocaleTimeString(), []);
return <div>{time}</div>;
-
优点:减少垃圾回收次数;代码简洁
-
缺点:时间锁定初始值;滥用易导致隐蔽的 BUG
这里解释一下所谓隐蔽的bug指的是什么
useMemo是用来缓存结果,避免重复计算的,但是时间这个东西,我们在很多时候属于要么不更新,要么频繁更新,在这种情况下,如果组件频繁挂载或者卸载的话,旧的格式化器无法被GC回收,同时累积大量的缓存对象,会造成内存膨胀。
-
适用场景:需要复杂计算的初始值缓存
4. useEffect基础动态更新
jsx
const [time, setTime] = useState('');
useEffect(() => {
const timer = setInterval(() => {
setTime(new Date().toLocaleTimeString());
}, 1000);
return () => clearInterval(timer);
}, []);
- 优点:实现动态更新时间;代码直观易理解
- 缺点:多组件实例导致定时器泛滥;父组件渲染可能打断计时
- 适用场景:独立组件的简单时钟
5. 单例模式 + 自定义 Hook
js
// 单例服务
const timeService = {
subscribers: new Set(),
start() {
setInterval(() => {
const time = new Date().toLocaleTimeString();
this.subscribers.forEach(cb => cb(time));
}, 1000);
}
};
// Hook封装
const useGlobalTime = () => {
const [time, setTime] = useState('');
useEffect(() => {
timeService.subscribers.add(setTime);
return () => timeService.subscribers.delete(setTime);
}, []);
return time;
};
- 优点:全应用共享单一定时器;内存占用恒定 O(1)
- 缺点:需要维护额外服务模块
- 适用场景:企业级应用;多组件时间同步需求
6. Web Worker 后台计算
js
// worker.js
self.onmessage = () => {
setInterval(() => {
self.postMessage(new Date().toLocaleTimeString());
}, 1000);
};
// 组件
useEffect(() => {
const worker = new Worker('worker.js');
worker.onmessage = (e) => setTime(e.data);
return () => worker.terminate();
}, []);
- 优点:不阻塞主线程;适合复杂计算场景
- 缺点:通信成本较高;增加构建复杂度
- 适用场景:计算密集型任务(如实时图表渲染)
7. Intl.DateTimeFormat 高效格式化
js
const formatter = useMemo(() =>
new Intl.DateTimeFormat('zh-CN', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
}), []);
const [time, setTime] = useState('');
useEffect(() => {
const timer = setInterval(() => {
setTime(formatter.format(new Date()));
}, 1000);
return () => clearInterval(timer);
}, []);
- 优点:性能比
toLocaleTimeString
快 3 倍;支持本地化配置 - 缺点:需手动管理格式化实例
- 适用场景:高频更新场景(如秒表);多语言/时区支持
项目中有很多很不起眼的代码,其实都可以进行优化,有的时候就是这些不起眼的小东西,累积起来会造成大麻烦,快去看看你的项目里有没有可以优化的时间吧,如果有更好的方法,欢迎评论区分享讨论