前端显示最新数据时,需要提示一个距离当前时间是多久。于是写出 Date.now() - timestamp
and format
。
然后,同事反馈最新数据显示的时间为负数,“- xx 秒钟之前”,让人摸不着头脑。我使用我的 PC、Mac、手机 查看这个数据,显示均为正常。再询问其它同事,事情似乎一切正常,就像是偶发性的奇怪 Bug。
这件事情,大概分析是 Date.now 返回的时间不太准确,估计会有 1 秒或几秒的偏差,一时也没想出太好的办法。
最近这段时间,这个问题越发明显了,我自己的 Mac 设备已经能看出问题了。于是先观察问题,在显示的逻辑上,加上一个报错报告,并修正最小为 0。通过观察报错数据,发现离谱的更多了。负数数据大小不一,小的有 -200ms,大的有负的一万多秒。当然能分析出时间太长的是 bot 的数据。
分析是否是设备系统更新出问题,还是 Chrome 浏览器一类问题,还是我们自己网站的代码更加复杂了?
- 网站代码复杂是可以怀疑的,因为有不确定地观察到,大的项目比小的项目更容易发生这个问题。
主要的负数在 -1 ~ -10 秒之间,大致都有分布。
解决
提出使用 server timestamp 去取代本地时间。
- 如何选择一个合适的 公用 api
一番寻找,并未找到合适的 api
。
插曲:搜索时间戳服务的过程中被误导进了一个
RFC 3161
清单,研究了一会发现这个是 时间戳证明,并不是我们需要的。
- 是否需要自己上线一个时间戳接口
细想过这个问题,若是上线这个接口,那么这个接口就会面临一个大量频繁请求的压力。鉴于之前的接口崩溃经验,前端实现一个简易接口不一定能完成这个任务。
打个比方,如果 3 秒请求一次,基于我们的用户量,这个接口不一定服务得好,实时性问题可能让这个问题变得更复杂。如果要 1 秒请求一次,那么这个事情就变得更复杂起来。并且会产生额外的服务费用。
把这件事情上升到 后端+运维+前端+... 一块完成这件又有点不必要。
- 请求自身官网,获取头部
AI 提示出,可以请求自身 URL,用 HEAD
请求,然后拿出请求头 headers 中的 Date
数据,这样可以成为一个 API 平替。Date 数据精度为 1 秒。
我多次 debug,返回时差会有 半秒左右的延迟。这个似乎可行,但还是会存在,循环 ping 接口的压力。
那有没有最佳的办法呢?
有的兄弟,有的。
目前的解决办法
获取头部信息,网站自身有很多请求,而代码中每个请求都会有 axios
的基础设置,只需要在 axios 中的拦截器中 response 中取出最新的 date header。
记得在 error.response 中也要获取一次
使用 Math.max
比较每个 server date,再比较 server date 与 Date.now,取出最大值。
这样可以不用新增新的请求,网站本身有持续的请求,没有新的服务压力。数据返回也保证了渲染的是最新的时间戳不会为负数。
performance
网站不存在秒级别请求,所以依旧会存在多秒的时差。所以可以通过最新一次的 server date 同时设置最新的 performance.now
,在使用最新 server 时间戳时,加上现在的差值再进行一步操作,达到更好的优化效果。
结语
现在的方案,能够解决负数的问题。依旧不是 100% 的修复,server date 存在秒级的误差,和请求返回的不确定耗时。通过这个方案似乎只能做到这一步了。
- 猜想 1:给每个 server date 设置一个精确度值(以 request time 为准),使用最准的 server date + performance 差值。
- 再叠加比较上面的最新 now,应该会有更好的效果
- 是否存在更好的 Date.now method?如果有就好了。