前言
在前端开发中,JavaScript 脚本的运行与界面的渲染是基于浏览器的事件循环机制。常用的浏览器事件包括:定时器事件、鼠标事件、键盘事件、网络事件等,这些事件的触发会引发 JavaScript 的执行,改变网页的状态与交互。
但是,在面对复杂的应用需求以及高性能、高流畅度的应用开发时,JavaScript 在应用渲染上的性能表现并不理想。因此,很多前端工程师会使用 requestAnimationFrame(以下简称 rAF)工具来优化网页流畅度,提升用户体验。下面本文就以此为主题进行阐述。
rAF 的原理解析
rAF(跟踪浏览器的刷新频率)是一种渲染动画的 API,它提供了一种更节省资源的方法来实现颜色、形状等的动画效果。使用 rAF 可以批量执行函数以达到优化性能的目的,因为它的执行时间是和屏幕的绘制时间同步的,可以充分利用浏览器的刷新频率,最大程度地减少计算数量,从而减少功耗。
下面我们来一步步分析 rAF 的工作原理:
- 页面持续渲染由浏览器帧率决定,目前主流浏览器的帧率是 60FPS
- rAF API 会在每次浏览器渲染完成后执行回调函数,实现定时刷新。
- 因为浏览器绘制频率不一定是稳定的,所以 rAF 会根据浏览器的帧率来调整执行回调函数的时间,以此来控制动画的流畅度。
rAF 的 API 实现
rAF 的 API 相较于 setTimeout 的 API 更加简单,函数的执行时间与浏览器的刷新频率同步,因此不需要设置时间间隔和 ClearInterval,更加适用于实时性要求较高的动画场景。
window.requestAnimationFrame(callback)
请求下一次重新渲染动画,如果浏览器是在当前的重绘中渲染我们的页面,那么这个请求则会被延迟,直到下一次绘制时才会触发回调事件。返回值是请求标识符,在使用该参数时需要注意。
callback 回掉函数会被传入一个单一参数,即回调本身,该参数仅仅在递归的调用中才存在。
使用示例代码:
// www.javascriptcn.com code example
// 兼容性写法
window.requestAnimationFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
setTimeout(callback, 1000 / 60);
};
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
// 兼容性写法结束
// 实际代码
function draw() {
console.log('draw a frame');
requestAnimationFrame(draw);
}
requestAnimationFrame(draw); // 启动动画
})();rAF 的优缺点
rAF 的 API 同样有其优缺点:
优点
- 节约资源:rAF API 会使函数在每次重新渲染时调用,而不是固定时间间隔调用。因此可以和浏览器的渲染很好的协同,使得计算只会在浏览器已经准备好的情况下调用,避免了计算浪费。
- 平滑度更好:rAF API 是浏览器内部自带的,它以浏览器的内部频率执行动画。这使得盒模型的移动更平滑,动画更自然。
- 可以在操作系统中带有休眠、节能等特性的设备上工作良好。例如,优化的固定时间间隔动画在电池供电的设备上可能运行得更慢,因为它需要在不需要时保持活动状态以便按计划更新的计时器。
缺点
- 对于非常密集的操作,可能会丢失一些帧,需要在适当的情况下适当地调整。实现和调试周期相对较长。
- 老旧版本的浏览器不支持 rAF 容易出现兼容性问题。
- 相比单独使用 rAF,使用 rAF 和 setTimeout 结合可以更加精细调控动画流程,达到更佳的效果。
rAF 和 setTimeout 的取舍
rAF 和 setTimeout 都可以用来实现动画效果,但是它们之间有一些差别,可以根据场景需求具体进行选择:
- 如果需要宏观精度的定时效果,使用 setTimeout
- 如果需要连续、高强度动画效果,使用 requestAnimationFrame
- 如果需要综合效果,最佳的方案可能是同时使用 requestAnimationFrame 和 setTimeout 混合算法
结语
总体来说,requestAnimationFrame 是实现动画效果的首选API,它能够高效地处理动画流程,减少卡顿现象的产生,可谓十分实用。
以上是本文分享的 rAF 原理解析与 API 书写,希望本文可以帮助各位前端工程师优化动画处理流程。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/677fce72ce7f4861251aa325