编程有意思

精确的时间

开的坑太多了,有时候自己都忘了,现在想吐槽点什么,都不知道放在哪个帖子里好,坑王实锤。

一个问题

前端显示时间,很基础的操作,基本学到 JS 就可以做了。一般就是设置一个定时器(setInterval),看英文其实是设置一个“间隔”,实际效果是间隔指定的时间执行对应的操作。所以间隔一秒,更新一下时间,我们就能看到页面中时间的般变化了。

道理上没问题,但是如果第一次我们在 1 秒 95 的时候获取时间,读取的秒数字是 1,显示出来,但这时候基本已经到 2 秒了,可是下次更新在一秒以后,就是 2 秒 95,于是这个显示就始终偏差接近一秒。偏差不大,一般没啥影响,所以大家也都不这么着了。

当然,如果看着这个时间抢秒杀就有点不靠谱,何况这个偏移程度还不固定。不过我们也要了解,这就是个电脑本地时间,即便现在有网络对时,也不是绝对精确,所以种种偏差叠加,这点细节真的不那么重要。

但有的网页时间不显示秒,于是有人想当然的把更新间隔设置为了一分钟,这就过了,同理上面,最多可能偏差接近一分钟。

第一种方法

怎么解决呢?收缩更新间隔,比如依然一秒更新一次,就比较准确了。

继续同理,那显示秒钟的呢,也收缩更新间隔,1 毫秒更新一次,准确了——并不是!JS 做不了那么小间隔的操作,会自己对齐到一个它所能执行的最小时间间隔,比如 15 毫秒一次。

但无论如何,这个问题算是解决了吧。可是频率过高的更新是不是有点浪费系统性能呢,单纯靠暴力换精度,就不太优雅。

第二种方法

在学习 setInterval 的同时,一定也都学习了 setTimeout。这就是一个一次性的定时器。

那么获取当前时间,看一下距离下一次更新的毫秒数(相对精确),设定一个计时器(setTimeout)用来触发下一次更新,如此循环往复……

精度提高,性能也差不太多,至少比高频好太多了。然后可能就遇到回调过深的问题了……

第三种方法

要不结合一下,用 setTimeout 调整第一次的偏移,让时间对齐,然后后面就用 setInterval 好了。

第一次只要对齐了,后面间隔一样,就应该都对齐了。这挺合理的。但是现在浏览器为了节省性能,可能对后台标签进行一定程度的暂停。会不会再次导致打乱……

第四种方法

还是 setInterval,间隔一秒执行一次,但是并不是直接更新时间,而是计算一下距离下一秒还有多少毫秒,设定一个定时器(setTimeout)在那个时间更新。

这样每次都调整一下偏差,比最初的方法性能消耗大概翻倍,但用在精确度为秒(或者更大)的场景下比较合理。能够在各种场景下保证相对精确,且性能消耗也不算过分。

但是有点小问题,如果因为程序的原因导致某些延迟,那么可能导致更新推迟,于是产生跳秒现象,解决办法是稍微收缩更新间隔,比如 900 毫秒更新一次。


其实有其他方法,但是大佬们的玩法我真看不懂,就用最基础的东西初步解决一下。精度上,第四种方法的偏差控制在大约 10 ms,日常可以接受了。

我在写油猴脚本中遇到一个问题
脚本的作用是获取网站数据里的一个文件链接,然后用油猴的GM_download(url,"我脚本自己定义的文件名")下载
这对于浏览器自带的下载来说,一切正常,下载得到的文件名也是我设置的
然而有的用户使用了IDM,自动拦截,改为用IDM下载,这时,他下载得到的文件名就是IDM根据链接自动获取的文件名(这个名称不方便阅读整理),而不是我脚本提供的文件名(方便阅读整理的)。

有什么办法对脚本做出一些改进,让IDM下载也能使用我脚本提供的文件名?

ps:最简单的办法当然是让用户在IDM上对此类链接网站设置为不自动下载,不去接管

放弃吧,喵喵喵!

我试了用链接的 download 属性被拦截的话也是一样的。我的理解是拦截到了文件网址,而没有获得修改文件名的要求(前端层面)。

办法么,也许可以先把文件读回来,然后前端修改一下再触发浏览器下载(这时候其实本质是从缓存取出)。你可以看看这一篇 前端实现文件下载并重命名(兼容IE) - 大可·Duke - 博客园 (我随便搜的)。我没测试,觉得如果这种情况被下载软件拦截的话也会变得挺复杂。我记得有网站使用类似的下载方法,叫什么来着,不过能当成特色并且没多少人追随的话,相比也有一定门槛。

所以在脚本上的话,不如放弃。

1 Like

mega