您的位置:首页 > 其它

必须了解的浏览器渲染性能

2016-11-14 21:36 204 查看
首先我们要明确的问题就是,一个网站除了样式好看,功能简单明了等限制用户浏览量的因素之外,还有什么原因是限制你的网站流量的原因。
渲染性能
在网站资源加载时,大多数用户关心的并不是网站如何加载,而是网站的加载速度,如果一个网站10秒,20秒,甚至30秒都无法加载成功,我相信没有那个用户会继续停留在这个网页上,所以我们必须要思考的问题就是,怎样的网站是顺畅的。下面的是google提出的数据模型:
   
Respond:0 – 100ms,视窗一般需要在这个时间段响应用户,超过这个时间段,用户就会感觉到延时。
Animation:0~16ms,屏幕每秒刷新60次,16ms 代表的是每一帧的时间。用户是非常关注动画的,当动画失帧很容易引起用户察觉。所以动画一般要控制在60FPS。
Idle:最大化主进程的空闲时间,这样可以及时响应用户输入。
Load:内容需要在1000ms 内加载出来,超过1000ms 会觉得加载缓慢。

如果想到达上面的性能需求我们可以从优化浏览器的渲染过程入手,首先让我们从浏览器解析一个页面来开始分析
  
转化: 浏览器从磁盘或网络读取 HTML 的原始字节,浏览器会将这段原始文件按照相应编码规范进行解码(现在一般为 utf-8)。
符号化:根据 W3C 标准转化为对应的符号(一般在尖括号内)。
DOM 构建:HTML 解析器会解析其中的 tag 标签,生成 token ,遇到 CSS 或 JS 会发送相应请求。HTML 解析时阻塞主进程的,CSS 一般也是阻塞主进程的(媒体查询时例外),也就是说它们在解析过程中是无法做出响应的。而 JS 手动添加 async 后达到异步加载,根据 token 生成相应 DOM 树。
CSSOM 构建,添加 CSS 样式生成 CSSOM 树。
渲染树构建,从 DOM 树的根节点开始,遍历每个可见的节点,给每个可见节点找到相应匹配的 CSSOM 规则,并应用这些规则,连带其内容及计算的样式。
样式计算,浏览器会将所有的相对位置转换成绝对位置等一系列的样式计算。
布局,浏览器将元素进行定位、布局。
绘制,绘制元素样式,颜色、背景、大小、边框等。
合成,将各层合成到一起、显示在屏幕上。
优化JavaScript的执行
函数的输入事件处理

首先,我们要知道的一个事实就是浏览器是由多个处理进程的:Compositor、Tile Worker、Main。当用户进行输入操作(滚动、点击等),如滚动时,Compositor 进程会接收到这个事件(实际它可以接受任何用户输入事件),如果可以的话,它将不会通知主进程,直接说:滚吧,牛宝宝。于是,页面就滚动了。当然,这其中包含更新层定位以及让
GPU 绘制帧,而主线程处于空闲状态。但是,事情往往并非如此。如果输入事件上绑定了 JS 处理事件的话,Compositor 进程就没办法主动跳过主进程了。
当 JS 处理事件过长时,输入事件的响应会一直处于阻塞状态,直到 JS 处理完成。当响应超过 100ms 时,用户就会感受到延时。所以当处理用户事件时,我们应该做到:

避免长时间的 JS 执行。
避免在处理中改变样式。因为样式改变会引起后面布局、绘制、合成等操作。
对用户输入进行消抖。
使用 requestAnimationFrame,将 setTimeout 换成 requestAnimationFrame,因为 setTimeout 时间控制可能造成在一帧的中间,目前各浏览器对 requestAnimationFrame 的支持已经比较好了。
使用 Web Workers,将复杂计算的 JS 采用 Web Workers 进行处理。
减少垃圾回收,垃圾回收是一个容易被忽略的问题,因为垃圾回收的时间是不受控制的,它可能在一个动画的中途,阻塞动画的执行,更理想的情况是在循环中复用对象。

样式优化
添加或移除一个 DOM 元素、修改元素属性和样式类、应用动画效果等操作,都会引起 DOM 结构的改变,从而导致浏览器需要重新计算每个元素的样式、对页面或其一部分重新布局(多数情况下)。
计算样式的第一步是创建一套匹配的样式选择器,浏览器就是靠它们来对一个元素应用样式的。第二步是根据匹配的样式选择器来获取对应的具体样式规则,计算出最终具体有哪些样式是要应用在 DOM 元素上的。所以,你只需要记住要减小选择器的复杂性,减少无效元素,从而减小样式的计算量
布局优化

避免触发布局

目前,transform 和 opacity 只会引起合成,不会引起布局和重新绘制。整个流程中比较耗费性能的布局和绘制流程将直接跳过,性能显然是很好的。其他的 CSS 属性改变引起的流程会有所不同,有些属性也会跳过布局,具体可以查看 CSS Triggers。所以,优化的第一步就是尽可能避免触发布局。
避免快速连续的布局

还有一种情况比强制同步布局更糟:连续快速的多次执行它

javascript 代码
效果预览

1234567function resizeAllParagraphsToMatchBlockWidth() {   // Puts the browser into a read-write-read-write cycle.  for (var i = 0; i < paragraphs.length; i++) {    paragraphs[i].style.width = box.offsetWidth + 'px';  }}
上述代码对一组段落标签执行循环操作,设置 p 标签的width属性值,使其与 box 元素的宽度相同。看上去这段代码是没问题的,但问题在于,在每次循环中,都读取了 box 元素的一个样式属性值,然后立即使用该值来更新 p 元素的 widt h属性。在下一次循环中读取 box 元素 offsetwidth 属性的时候,浏览器必须先使得上一次循环中的样式更新操作生效,也就是执行布局过程,然后才能响应本次循环中的样式读取操作。布局过程将在每次循环中发生。优化代码:
javascript 代码效果预览
12345678var width = box.offsetWidth; function resizeAllParagraphsToMatchBlockWidth() {  for (var i = 0; i < paragraphs.length; i++) {    // Now write.    paragraphs[i].style.width = width + 'px';  }}
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  浏览器 性能优化