setTimeout(fn, 15)这样的东西到底有没有意义?
2016-04-22 15:05
591 查看
Review
setTimeout/setInterval是JavaScript中很常见的两个超时函数,常用来制作动画或者异步操作(setTimeout(fn, 0))。
setTimeout(fn, delay)中的第二个参数是
delay是一个以毫秒为单位的整数,表示经过 delay 时间后开始调用fn。但是由于JavaScript是单线程的,setTimeout这类通过web API的调用会被维护在一个队列中,所以fn真正调用的时间是 >= delay 。
正题
在今年秋招面试的时候被问到了关于setTimeout的限制的问题,一下子就懵掉了。超时调用和异步的问题都知道,但是从来没想过setTimeout会有什么限制。后来面试快结束的时候和面试官(Givon)聊了一下他说 当delay<16的时候delay是没有意义的 。然后撸主真的是涨姿势了,从来没听说过这个问题,但是 16 这个数字让我有点纠结。
百度查了很多资料都没有这方面的内容,后来想起张鑫旭的一篇关于requestAnimationFrames 博客,里面有讨论过关于浏览器帧频的问题。感觉Givon说的应该就是这个问题。
里面有提到由于很大一部分浏览器刷新频率都是16ms,所以使用超时函数制作动画的时候如果设置的时间没有卡紧帧频的话有可能会出现掉帧的情况。因此才会出现了
requestAnimationFrame这个替代方案。
后来在知乎上看过类似的讨论,撇开动画不说 delay的极限值取决于处理器的性能 。感觉这个结论更接近正确的答案。
写了一个小demo测试一下:
var handler, prev = Date.now(), count = 0, current; handler = setInterval(function() { current = Date.now(); console.log(current - prev); prev = current; count++; if(count >= 100) clearInterval(handler); }, 1);
结果(还没弄好图床,就不贴图了):
62 4 2 2 4 7 5 6 5 ...
除了第一个62s外,超时还算是平均,基本维持在5s左右。
在写demo代码的时候想到
console.log这种IO操作会不会大幅度拖慢执行速度造成结果不准确,然后先采用了数组缓存结果再统一输出:
var arr = [], handler, prev = Date.now(); handler = setInterval(function() { var current = Date.now(); arr.push(current - prev); prev = current; if(arr.length >= 100) clearInterval(handler); }, 1); console.dir(arr);
后来发现两者的速度基本没差多少,然后我内心就一片卧槽了。console.log的效率那么高直逼内存了?谷歌大法好?
后来想了一下还有另外一个可能,后来百度了一下,证实了这个猜想: console.log其实是一个异步操作 = =。。。所以平时输出的时候结果有可能不对。用了这玩意那么多年,现在才知道真是孤陋寡闻了。
Summary
setTimeout(fn, 15)这样的函数在在制作动画的时候一般是没有意义的,为了避开掉帧的风险享受丝般顺滑的动画效果可以使用requestAniamtionFrame来替代(旧浏览器可能存在一定兼容问题)。但是撇开动画(除了动画我还真想不出还有什么需要这么高频超时运作的场景),delay<15还是能跑的。相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- JavaScript演示排序算法
- javascript实现10进制转为N进制数
- html5 web数据存储
- 最后一次说说闭包
- Ajax
- SEO
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 对一个分号引发的错误研究
- 异步流程控制:7 行代码学会 co 模块
- [译] React 入门
- ES6 走马观花(ECMAScript2015 新特性)
- JavaScript拆分字符串时产生空字符的原因
- Canvas 在高清屏下绘制图片变模糊的解决方法