前言
不久前,苹果发布了最新款iPhone13
,其中的Pro
型号更是史无前例地用上了120Hz ProMotion
刷新率的屏幕,并且宣称其刷新率可以在10
赫兹到120
赫兹之间动态变化以适配具体的场景需求。
于是我想到了之前做canvas
开发抽象出来的动画类的代码,似曾相识的感觉。
高刷屏
众所周知,屏幕具备一个刷新率,通常其值为60Hz
,也就是说1
秒渲染60
次,而通常我们所看的视频的帧率一般为30Hz
,而电影制式一般为24Hz
。
通常,刷新率越高,人眼在每秒所观测到的画面越多,那么从视觉观感来说就会越流畅,人所进行的操作通过屏幕反映出来也就更迅速,所以,职业电竞选手,特别是FPS
选手,他们给自己挑选的显示器几乎都是144Hz
的刷新率往上走,更有甚者刷新率达到了240Hz
。
苹果的革新
所以,当手指触摸在屏幕上产生了事件或触发了动画时,屏幕立即以最高120
帧率运行,这样子保证了用户最佳的体验;而当用户在阅读静止不动的页面时,屏幕恢复到10
帧率进行刷新,这样既保证了极佳的用户体验,又大大减少了由于无效重绘而引起的耗电量。
再打个额外的比方,假设正常情况下,我们看一段每秒30
帧的视频耗了10%
的电,实际上在60Hz
的屏幕上,每2
帧所渲染出来的视频内容都是一模一样的,此时,动态刷新率登场,将帧率动态地调整为30Hz
,那么大致可以说,耗电量可以接近于5%
,接近于之前的一半,而实际体验和之前一模一样,可谓是完完全全的物尽其用。
requestAnimationFrame
我不知道苹果系统在底层
对于动态刷新率是如何处理的,但我可以说,至少我在HTML5
的上层应用层
是完完全全可以做到动态刷新的。
HTML5
中,有这么一个方法requestAnimationFrame
,它在浏览器中属于window
对象,处于全局作用域中。
通常,调用此方法,传入需要执行的方法的句柄:
function doSomething(timestamp) {
console.log(timestamp);
}
requestAnimationFrame(doSomething);
它申请了一个回调,在页面下一帧刷新时,执行doSomething
方法,其中的timestamp
参数是执行方法时的时间戳。
输出如图:
而如果我们要用此方法写一个动画,只需要在doSomething
方法中再次调用requestAnimationFrame
即可,如下所示:
function doSomething(timestamp) {
console.log(timestamp);
requestAnimationFrame(doSomething);
}
输出如图:
requestAnimationFrame
使得浏览器在每一帧刷新时进行方法的回调,所以它在正常情况下即是以显示器最高帧率进行回调的。
实现
有的没的撤了一堆,接着写点有意思的,也就是说实现类似苹果的动态刷新率。
既然requestAnimationFrame
是以最高帧率运行的,那么如果我们设置一个是否执行的前提判断,岂不是就限制了帧率吗?
也就是说,假如我们想要将刷新率动态限制到fps
值,那么每次执行间隔应该是1000 / fps
,只有当前时间
减去上一次执行的时间
大于这个时间间隔
时,才执行自己的逻辑,那么不就实现了动态刷新率了吗?
var fps = 2; // 在此,我将 fps 限制在 2 帧每秒
var last = 0; // 上次的时间戳
function doSomething(timestamp) {
if (timestamp - last >= 1000 / fps) { // 当大于时间间隔时执行逻辑
console.log(timestamp); // 此处执行具体逻辑
last = timestamp; // 将时间戳记录给 last
}
requestAnimationFrame(doSomething);
}
requestAnimationFrame(doSomething);
输出如图:
示例
我用canvas
写了一个示例,有兴趣的可以自己手动尝试:CodePen 在线演示。
- 鼠标处于界面外时,刷新率被我主动限制在
10Hz
; - 鼠标移入界面内时,刷新率动态改变至
30Hz
; - 而当鼠标被按下时,刷新率动态改变至最高帧率。
可以很明显的看到,画面中小球执行动画的流畅度。
结论
在HTML5 canvas
动画开发中,实现动态刷新率并不是一件很难的事情,由此我也想到,既然顶层应用层
能做到的事,iOS 底层
从理论上来说动态刷新率这个技术不应该只是iPhone13 Pro
系列所能享有的,因为它和屏幕
的素质实在无关,而是在软件
层面限制何时应该进行事件回调。
所以,完全有理由期待一下,苹果在未来将此项技术应用给全部产品线也未可知呢?
欢迎批评指正!