前端显示最新数据时,需要提示一个距离当前时间是多久。于是写出 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?如果有就好了。