YYSuni
cover

负数时差

计算数据距离当前时间有多久,居然出现很多负数的反馈。

前端显示最新数据时,需要提示一个距离当前时间是多久。于是写出 Date.now() - timestamp and format

然后,同事反馈最新数据显示的时间为负数,“- xx 秒钟之前”,让人摸不着头脑。我使用我的 PC、Mac、手机 查看这个数据,显示均为正常。再询问其它同事,事情似乎一切正常,就像是偶发性的奇怪 Bug。

这件事情,大概分析是 Date.now 返回的时间不太准确,估计会有 1 秒或几秒的偏差,一时也没想出太好的办法。

最近这段时间,这个问题越发明显了,我自己的 Mac 设备已经能看出问题了。于是先观察问题,在显示的逻辑上,加上一个报错报告,并修正最小为 0。通过观察报错数据,发现离谱的更多了。负数数据大小不一,小的有 -200ms,大的有负的一万多秒。当然能分析出时间太长的是 bot 的数据。

分析是否是设备系统更新出问题,还是 Chrome 浏览器一类问题,还是我们自己网站的代码更加复杂了?

  • 网站代码复杂是可以怀疑的,因为有不确定地观察到,大的项目比小的项目更容易发生这个问题。

主要的负数在 -1 ~ -10 秒之间,大致都有分布。

解决

提出使用 server timestamp 去取代本地时间。

  1. 如何选择一个合适的 公用 api

一番寻找,并未找到合适的 api

插曲:搜索时间戳服务的过程中被误导进了一个 RFC 3161 清单,研究了一会发现这个是 时间戳证明,并不是我们需要的。

  1. 是否需要自己上线一个时间戳接口

细想过这个问题,若是上线这个接口,那么这个接口就会面临一个大量频繁请求的压力。鉴于之前的接口崩溃经验,前端实现一个简易接口不一定能完成这个任务。

打个比方,如果 3 秒请求一次,基于我们的用户量,这个接口不一定服务得好,实时性问题可能让这个问题变得更复杂。如果要 1 秒请求一次,那么这个事情就变得更复杂起来。并且会产生额外的服务费用。

把这件事情上升到 后端+运维+前端+... 一块完成这件又有点不必要。

  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?如果有就好了。
TABLE OF CONTENTS