苦逼前端

尝试使用requestAnimationFrame来解决之前提到的GUI渲染问题

Javascript2014-01-12 01:38

这个问题搁置了很久:关于Chrome/Firefox最小化后停止GUI渲染的问题

据说requestAnimationFrame可以解决,只是大致去网上搜了搜关于这个函数的一些信息。并未亲自尝试。MSDN这样介绍的:基于脚本的动画的计时控制

看了半天,发现原来setTimeout和setInterval这一对货色在设置的间隔很小时,可能会丢帧。也就是我们所了解的"最小间隔"。因为浏览器在渲染当前请求的时候,可能又接收了别的渲染请求,导致了"几个请求同时渲染"的情况。

但是requestAnimationFrame的原理是在浏览器渲染完毕当前请求后才会接收下一个请求,相当于它可以直接触发渲染操作,下一次请求只有在当前渲染操作完毕后才会进来(个人理解)。这样就有效的防止了丢帧和过度重绘等问题。

由于它的这种特性,或许可以对我们上面提到的那个问题有所帮助?因为在浏览器最小化或者切到别的tab的时候,浏览器是停止渲染的,也就是说,浏览器同样也不会再接收到渲染请求,只有当下一次进入这个页面,渲染完毕当前请求,下一次请求才会进来。

正巧它几乎可以支持所有现代浏览器,这样我们在低版本IE下仍然使用常规的setTimeout和setInterval(浪费就浪费吧,谁让它那么不争气...),高级浏览器就使用requestAnimationFrame,或许可以完爆这个问题。

但是似乎有些图样图森破了。这个函数,只是在浏览器接收渲染请求并渲染完毕的时候,会再次发送渲染请求,那么意味着,他只可以用于基础动画,单张滚动图片的场景。

那么如何来实现间隔几秒钟滚动一张图片呢?难道再在外面用setInterval/setTimeout来控制几秒滚动一次?这样似乎同样会引发之前提到的问题。因为这俩货色,即使浏览器不在当前视图的情况下,依然会不停的运行,"囤积"渲染请求。

后来想到了一个方法,requestAnimationFrame相当于是一个页面渲染的监听器,当页面发生渲染并渲染完毕后会执行它的回调函数,那么我们只要在回调函数中判断是否完整滚完一张图片就可以了。如果是完整滚完一张图片了,那么设置一个setTimeout,比如每滚一张要间隔2s,那么就把时间设为2000ms,如果还未滚完一张图片,那么就递归这个渲染函数。这样,只有在页面发生了渲染才会有可能有这个setTimeout。这样似乎问题就解决了。

我做了一下尝试:改进后的轮播图(由于用的原生js,未做事件支持,懒...)

这样,即使再切到别的tab或者最小化浏览器,页面停止GUI渲染,js也不会再执行代码了,皆大欢喜。

但是有这样一个问题:当正好滚完一张图片的时候,切到别的tab或者最小化浏览器,这时候setTimeout延时函数已经开启,所以当过一段时间再切回来的时候,延时的2s就被'私吞了',会直接滚到下一张。不过这也无伤大雅了。

评论(1)
  • 106.38.223.*: 嗯嗯嗯嗯嗯嗯嗯嗯嗯嗯嗯嗯嗯嗯嗯嗯5年6个月前
还可输入200个字