延时函数的不准确性
浏览器时钟精度
浏览器的时钟精度就是浏览器更新时钟的频率。更新的越频繁,那么时间也就越准确。
现在浏览器的最小精度为4ms,但并不意味着频率时刻保持在4ms。仔细分析一下,“更新操作”对电脑来说是比较烧脑的,脑子稍微差点的cpu反应慢,精度就低。事实上,除了cpu硬件之外,操作系统(OSX和windows下不同)以及浏览器内核都会影响到浏览器的精度;其次,电脑本身的调节机制,尤其是笔记本。笔记本在使用电池供电的时候,精度就会被自动降低从而达到保护电源的作用。所以最小精度4ms只是当今浏览器的最高水平,显示情况下是不会达到这一精度。
延时函数的不准确性
在人类的眼中或许感觉不到setTimeout()和setInterval()存在误差,毕竟ms级的时间太短暂了。但事实上确实存在着误差。下面来讲误差从何而来。
setTimeout(fn,15ms);
我们先设置了这样一个延时处理的函数,fn函数
被添加到队列当中,预计15ms
之后执行。
过去的浏览器时间精度在10ms~15.6ms之间已经是极限了,那么我们就假设我们使用的浏览器的时间精度为10ms。
函数等待时间 |--------------| 15ms
浏览器刷新 |--------||----------| 20ms
当第一个10ms之后,浏览器刷新了时间,发现“我靠,跑了这么久,还没有到点”,于是又发动第二次刷新。第二次刷新结束之后,20ms已经过去了,函数才到了执行期,并且比预期要多等了5ms。
我们知道,浏览器执行js和更新界面是共用一个线程的,当线程空闲时,它会从任务队列中取任务来运行。所以当函数到了执行期时,它会被添加到队列当中,但是不一定立即执行,如果队列中还有其他任务,单线程的规则就会导致这个函数需要等待前面的任务执行完才可以执行。
基于这两点原因,setTimeout()和setInteval()在微世界中,其实并不守时,这是无法控制且无奈的事情。
从上面可以看出,浏览器的精度越小,那么误差也就越小。嗯 ~ ~ 排队时间无法预算,只能求老天保佑了。