深度剖析浏览器渲染性能原理,你到底知道多少?

渲染卡顿是怎么回事?

网页不仅应该被快速加载,同时还应该流畅运行,比如快速响应的交互,如丝般顺滑的动画等。

大多数设备的刷新频率是60次/秒,也就说是浏览器对每一帧画面的渲染工作要在16ms内完成,超出这个时间,页面的渲染就会出现卡顿现象,影响用户体验。

为了保证页面的渲染效果,需要充分了解浏览器是如何处理HTML/JavaScript/CSS的。

渲染流程分为几步?

1、JavaScript:JavaScript实现动画效果,DOM元素操作等。

2、Style(计算样式):确定每个DOM元素应该应用什么CSS规则。

3、Layout(布局):计算每个DOM元素在最终屏幕上显示的大小和位置。由于web页面的元素布局是相对的,所以其中任意一个元素的位置发生变化,都会联动的引起其他元素发生变化,这个过程叫reflow。

4、Paint(绘制):在多个层上绘制DOM元素的的文字、颜色、图像、边框和阴影等。

5、Composite(渲染层合并):按照合理的顺序合并图层然后显示到屏幕上。

结合渲染流程怎么优化渲染性能呢?

结合上述的渲染流程,我们可以去针对性的分析并优化每个步骤。

1、优化JavaScript的执行效率

2、降低样式计算的范围和复杂度

3、避免大规模、复杂的布局

4、简化绘制的复杂度、减少绘制区域

5、优先使用渲染层合并属性、控制层数量

6、对用户输入事件的处理函数去抖动(移动设备)

优化JavaScript的执行效率,具体可以做什么?

1、动画实现,避免使用setTimeout或setInterval,尽量使用requestAnimationFrame。

setTimeout(callback)和setInterval(callback)无法保证callback函数的执行时机,很可能在帧结束的时候执行,从而导致丢帧。requestAnimationFrame(callback)可以保证callback函数在每帧动画开始的时候执行。

2、把耗时长的JavaScript代码放到Web Workers中去做。

JavaScript代码运行在浏览器的主线程上,与此同时,浏览器的主线程还负责样式计算、布局、绘制的工作,如果JavaScript代码运行时间过长,就会阻塞其他渲染工作,很可能会导致丢帧。

前面提到每帧的渲染应该在16ms内完成,但在动画过程中,由于已经被占用了不少时间,所以JavaScript代码运行耗时应该控制在3-4毫秒。

如果真的有特别耗时且不操作DOM元素的纯计算工作,可以考虑放到Web Workers中执行。

3、时间分片,把DOM元素的更新划分为多个小任务,分别在多个frame中去完成。

由于Web Workers不能操作DOM元素的限制,所以只能做一些纯计算的工作,对于很多需要操作DOM元素的逻辑,可以考虑分步处理,把任务分为若干个小任务,每个任务都放到requestAnimationFrame中回调执行。

降低样式计算的范围和复杂度,具体可以做什么?

添加或移除一个DOM元素、修改元素属性和样式类、应用动画效果等操作,都会引起DOM结构的改变,从而导致浏览器需要重新计算每个元素的样式,对整个页面或部分页面重新布局,这就是所谓的样式计算。

样式计算主要分为两步:创建一套匹配的样式选择器,为匹配的样式选择器计算具体的样式规则。

1、降低样式选择器的复杂度,尽量保持class的简短,或者使用Web Components框架。

2、减少需要执行样式计算的元素个数。

由于浏览器的优化,现代浏览器的样式计算直接对目标元素执行,而不是对整个页面执行,所以我们应该尽可能减少需要执行样式计算的元素的个数。

避免大规模、复杂的布局,具体可以做什么?

布局就是计算DOM元素的大小和位置的过程,如果你的页面中包含很多元素,那么计算这些元素的位置将耗费很长时间。

布局的主要消耗在于:1. 需要布局的DOM元素的数量;2. 布局过程的复杂程度。

1、尽可能避免触发布局,引发DOM回流。

当你修改了元素的属性之后,浏览器将会检查为了使这个修改生效是否需要重新计算布局以及更新渲染树,对于DOM元素的“几何属性”修改,比如width/height/left/top等,都需要重新计算布局。

2、避免强制同步布局事件的发生。

前面提过,将一帧画面渲染的屏幕上的流程是:首先是JavaScript脚本,然后是Style,然后是Layout,但是我们可以强制浏览器在执行JavaScript脚本之前先执行布局过程,这就是所谓的强制同步布局。

在JavaScript脚本运行的时候,它能获取到的元素样式属性值都是上一帧画面的,都是旧的值。因此,如果你在当前帧获取属性之前又对元素节点有改动,那就会导致浏览器必须先应用属性修改,结果执行布局过程,最后再执行JavaScript逻辑。

简化绘制的复杂度、减少绘制区域,具体可以做什么?

绘制就是填充像素的过程,通常这个过程是整个渲染流程中耗时最长的一环,因此也是最需要避免发生的一环。

如果Layout被触发,那么接下来元素的Paint一定会被触发。当然纯粹改变元素的非几何属性,也可能会触发Paint,比如背景、文字颜色、阴影效果等。

1、提升移动或渐变元素的绘制层。

绘制并非总是在内存中的单层画面里完成的,实际上,浏览器在必要时会将一帧画面绘制成多层画面,然后将这若干层画面合并成一张图片显示到屏幕上。

这种绘制方式的好处是,使用transform来实现移动效果的元素将会被正常绘制,同时不会触发其他元素的绘制。

2、减少绘制区域。

浏览器会把相邻区域的渲染任务合并在一起进行,所以需要对动画效果进行精密设计,以保证各自的绘制区域不会有太多重叠。

3、简化绘制的复杂度。

可以实现同样效果的不同方式,我们应该采用性能更好的那种。

优先使用渲染层合并属性、控制层数量,具体可以做什么?

1、使用transform/opacity实现动画效果。

使用transform/opacity实现动画效果,会跳过渲染流程的布局和绘制环节,只做渲染层的合并。使用transform/opacity的元素必须独占一个渲染层,所以必须提升该元素到单独的渲染层。

2、提升动画效果中的元素。

应用动画效果的元素应该被提升到其自有的渲染层,但不要滥用。

在页面中创建一个新的渲染层最好的方式就是使用CSS属性will-change,对于目前还不支持will-change属性、但支持创建渲染层的浏览器,可以通过3D transform属性来强制浏览器创建一个新的渲染层。需要注意的是,不要创建过多的渲染层,这意味着新的内存分配和更复杂的层管理。

尽管提升渲染层看起来很诱人,但不能滥用,因为更多的渲染层意味着更多的额外的内存和管理资源,所以当且仅当需要的时候才为元素创建渲染层。

对用户输入事件的处理函数去抖动(移动设备),具体可以做什么?

用户输入事件处理函数会在运行时阻塞帧的渲染,并且会导致额外的布局发生。

1、避免使用运行时间过长的输入事件处理函数。

理想情况下,当用户和页面交互,页面的渲染层合并线程将接收到这个事件并移动元素。这个响应过程是不需要主线程参与,不会导致JavaScript、布局和绘制过程发生。

但是如果被触摸的元素绑定了输入事件处理函数,比如touchstart/touchmove/touchend,那么渲染层合并线程必须等待这些被绑定的处理函数执行完毕才能执行,也就是用户的滚动页面操作被阻塞了,表现出的行为就是滚动出现延迟或者卡顿。

2、避免在输入事件处理函数中修改样式属性。

输入事件处理函数,比如scroll/touch事件的处理,都会在requestAnimationFrame之前被调用执行。

因此,如果你在上述输入事件的处理函数中做了修改样式属性的操作,那么这些操作就会被浏览器暂存起来,然后在调用requestAnimationFrame的时候,如果你在一开始就做了读取样式属性的操作,那么将会触发浏览器的强制同步布局操作。

3、对滚动事件处理函数去抖动。

通过requestAnimationFrame可以对样式修改操作去抖动,同时也可以使你的事件处理函数变得更快。

深度剖析浏览器渲染性能原理,你到底知道多少?相关推荐

  1. 单文件浏览器_图文并茂深度解析浏览器渲染原理,包看懂超值得收藏

    在我们面试过程中,面试官经常会问到这么一个问题,那就是从在浏览器地址栏中输入URL到页面显示,浏览器到底发生了什么?这个问题看起来是老生常谈,但是这个问题回答的好坏,确实可以很好的反映出面试者知识的广 ...

  2. 浏览器内存不足导致页面崩溃_深度精读:浏览器渲染原理 [8000字图文并茂]

    原文地址:https://segmentfault.com/a/1190000022633988作者:_杨溜溜 在我们面试过程中,面试官经常会问到这么一个问题,那就是从在浏览器地址栏中输入URL到页面 ...

  3. 浏览器渲染页面原理,reflow、repaint及其优化

    浏览器的主要组件包括: 1.      用户界面 - 包括地址栏.前进/后退按钮.书签菜单等.除了浏览器主窗口显示的你请求的页面外,其他显示的各个部分都属于用户界面. 2.      浏览器引擎 - ...

  4. iOS之深度剖析UIScrollView的实现原理与阻尼动画

    一.前言 UIScrollView 是 iOS 开发中不可或缺也是使用最多的基础组件,常用的 Feed 流.Pager.轮播图等等,都与其存在密不可分的联系.日常开发中,我们通常局限于必要的几个调用接 ...

  5. 天线开路短路检测原理_深度剖析开短路测试原理

    开短路测试应用非常的广泛, 只要特别的指出相关行业, 所谓的开短路测试, 都是指测试邦定线的开短路测试, IC 的开短路测试. 开短路测试,是测试工程师需要掌握的最基本的技能,通常被称为 conTIn ...

  6. 【Web动画】CSS3 3D 行星运转 浏览器渲染原理

    承接上一篇:[CSS3进阶]酷炫的3D旋转透视 . 最近入坑 Web 动画,所以把自己的学习过程记录一下分享给大家. CSS3 3D 行星运转 demo 页面请戳:Demo.(建议使用Chrome打开 ...

  7. 网站性能优化实战(二)——深入浅出浏览器渲染机制

    --从Webkit内部渲染机制出发,谈网站渲染性能优化 本文是对前文:imweb.io/topic/5b6fd- 相关知识的补充,文中的"前文"一词同此. 特以此文向<Web ...

  8. 布隆过滤器原理深度剖析

    HBase布隆过滤器原理深度剖析 1. 数据结构与原理 1.1 初始化 1.2 变量映射 1.3 变量检索 1.4 总结 2. 过滤器特性 2.1 误判率 2.2 判断特点 3. 案列代码 1970年 ...

  9. 唯一插件化Replugin源码及原理深度剖析--插件的安装、加载原理

    上一篇 唯一插件化Replugin源码及原理深度剖析–唯一Hook点原理 在Replugin的初始化过程中,我将他们分成了比较重要3个模块,整体框架的初始化.hook系统ClassLoader.插件的 ...

最新文章

  1. 一个奇葩的标志寄存器 flag寄存器
  2. 080_html5 Canvas和SVG
  3. java HashMap问题
  4. html5输入框自动放大镜,JS 仿支付宝input输入显示数字放大镜
  5. 阅读react-redux源码(七) - 实现一个react-redux
  6. 计算机在职研究生网络班,在职研究生网络班是什么意思
  7. aes解密算法 java_AES算法实现Java和JS互通加解密
  8. C语言-指针的比较/指针加减
  9. 利用自定义事件实现不同窗体间的通讯 -- C#篇
  10. map的基本操作总结C++
  11. heeds matlab,Isight FD4-CAE优化软件 与HEEDS对比
  12. C语言程序设计题解pdf,C语言程序设计题解与上机指导.pdf
  13. PyTorch使用多GPU并行训练及其原理和注意事项
  14. 通信领域的宽带信号和窄带信号到底是什么??
  15. 2018谷歌开发者节深圳站,Testin云测的AI应用案例获广泛关注
  16. Invoking “cmake“ failed报错
  17. videojs+hls+rtmp流媒体播放
  18. 模块5-6 冗余网络
  19. 农村养老保险系统Mysql_2020年农村养老保险管理系统(在线查询)
  20. hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

热门文章

  1. 与 Brian Kernighan 一起回忆 Unix 的诞生!
  2. 进程全家桶,看这一篇就够了 | 原力计划
  3. 程序员分析一线城市 1000 +岗位招聘需求,告诉你如何科学找工作
  4. 中国开源产品如何走向世界?
  5. 跟风 Google 只是东施效颦?!
  6. Python 爬取 3000 部电影,最具人气烂片排行榜出炉!
  7. 首款“印度制造”的微处理器 AJIT 面世!
  8. Facebook 的 AI 翻身之战!
  9. 知乎 2019 新知青年大会开幕,用问题改变世界的方向
  10. Unity 引擎 14 年!开发者除了游戏还可以用它来做什么?