浏览器-04 WebKit 渲染2
2015-12-11 19:48
162 查看
渲染主循环(main loop)和requestAnimationFrame
requestAnimationFrame
使用requestAnimationFrame而非
setTimeout/setInterval绘制动画;
requestAnimationFrame:告诉浏览器
JavaScript想发起一个动画帧,然后在动画帧绘制之前,需要做一些动作,这样浏览器可以根据需要来优化自己的
mainloop机制和调用时间点,以达到较好地平衡效果;
var start = null; var element = document.getElementById("example"); function step(timestamp) { if (!start) start = timestamp; var progress = timestamp - start; element.style.left = Math.min(progress/10, 200) + "px"; if (progress < 2000) { window.requestAnimationFrame(step); } } window.requestAnimationFrame(step);
渲染mainloop
mainloop
过程
chromium是多进程的结构,
Browser进程用户界面的
mainloop和
Renderer进程的主线程的
mainloop分别位于两个不同的进程,所以
UI和渲染可以互相不影响;
但是
Renderer进程的渲染工作和
JavaScript的执行工作都在其主线程中,由
mainloop来负责调度完成,存在竞争;
过程:大的循环加上一个事件队列
当队列中有事件时,从队列中取出第一个事件,设置相应的状态信息,处理该事件及其对应的处理函数,直到该函数处理完后,才重新检查队列中是否有事件;
如果有,继续处理;如果没有,则继续等待;
存在问题:
如果队列中事件多,很多事件可能来不及处理,造成比较大的延时,因而事件的平均等待时间会比较长;
如果事件的处理函数需要的时间很长,就会造成后面的事件一直在等待,同样会增加事件的平均等待时间;
WebKit
和Chromium
中的实现
setTimeout和
setInterval的实现:
WebKit会为
DOM中的每个
setTimeout和
setInterval的调用创建一个
DOMTimer,而后该对象会由存储
TLS(thread localstorage)中的
ThreadTimers负责管理,其内部其实是一个最小堆,每次取
timeout最小时间,同时,相同的
Timer可以合并;
当
Timer超时后,
Chromium清除该
Timer对象,同时调用相应的回调函数,回调函数通常会更新页面的样式和布局, 这会触发
relayout,从而触发立即重新绘制一个新帧;
setTimeout和
setInterval从不考虑浏览器内部发生了其他什么事,它只要求浏览器在某个时间之后调用它的回调函数,无论浏览器很繁忙或者页面被隐藏;
requestAnimationFrame的实现原理就是其会申请绘制下一帧, 时间由浏览器决定,只需要浏览器在绘制下一帧前执行其设置的回调函数,完成
JavaScript对动 画所做的设置和逻辑即可;
JavaScript调用
requestAnimationFrame,相应的
webkit和
chromium会调度一个需要绘制下一证的事件,该事件会将
requestAnimationFrame的调用上下文和回调函数记录下来;
上面的请求会触发
Chromium更新页面内容的事件,该事件被
mainloop调度处理后,会检查是否需要调用动画的相关处理,如果有动画需要处理,就会依次调用那些回调函数,
JavaScript引擎会更新相应的
CSS属性或者
DOM树修改;
Chromium触发重新计算
layout,更新自己的
Renderer树,而后绘制完成一帧的渲染;
为了实现更好的性能,
chromium中对
requestAnimationFrame有三个设计原则:
当页面不可见时,其回调函数不会被调用,这可以减少
CPU和
GPU的使用率;
其最大调用频率不会超过
60hz,无论屏幕的刷新率是多少,;因而回调函数也不会每秒调用超过60次,这是因为
60FPS已经能够满足
UI流畅的要求了;
只有当页面真正开始渲染时,回调函数才会被调用;
设计机制带来的编程考虑
回调函数不能太大,不能占用太长时间,否则会影响页面的响应和绘制的频率;requestAnimationFrame不需要设置间隔时间,不同刷新率的间隔时间不一样,这完全由浏览器来控制,而不需要操心;
回调函数无需合并,可以在任意位置设置回调函数,它们可以被浏览器集中处理, 而无需要一个统一的入口;
相关文章推荐
- JS组件系列——Bootstrap寒冬暖身篇:弹出框和提示框效果以及代码展示
- CCFlow与JFlow的集成模式的组织结构说明
- poj 1276 Cash Machine 裸的多重背包 ★
- 链接器工具错误 LNK2019 C++primer5第十五章程序错误的解决
- 设计模式系列(十)适配器模式(Adapter Pattern)
- win7 装redis
- Android和JavaScript相互调用初学
- APUE学习之----进程通信实现消息队列
- XUPorter——修改导出后的XCode工程
- 23种设计模式C++实例之单例模式
- USACO 1.2
- python练习
- 命令行选项
- 该读书的时候读书
- Objective-C 面向对象一
- POJ 3213 PM3 矩阵乘法
- Oracle 如何在线添加ASM磁盘
- [LeetCode]:Two Sum
- iOS常见错误6-The identity used to sign the executable is no longer valid.
- Objective-C语言——封装、拆包基本数据类型