浏览器工作原理与实践
李兵
前盛大创新院高级研究员
立即订阅
6167 人已学习
课程目录
已完结 42 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 参透了浏览器的工作原理,你就能解决80%的前端难题
免费
宏观视角下的浏览器 (6讲)
01 | Chrome架构:仅仅打开了1个页面,为什么有4个进程?
02 | TCP协议:如何保证页面文件能被完整送达浏览器?
03 | HTTP请求流程:为什么很多站点第二次打开速度会很快?
04 | 导航流程:从输入URL到页面展示,这中间发生了什么?
05 | 渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的?
06 | 渲染流程(下):HTML、CSS和JavaScript,是如何变成页面的?
浏览器中的JavaScript执行机制 (5讲)
07 | 变量提升:JavaScript代码是按顺序执行的吗?
08 | 调用栈:为什么JavaScript代码会出现栈溢出?
09 | 块级作用域:var缺陷以及为什么要引入let和const?
10 | 作用域链和闭包 :代码中出现相同的变量,JavaScript引擎是如何选择的?
11 | this:从JavaScript执行上下文的视角讲清楚this
V8工作原理 (3讲)
12 | 栈空间和堆空间:数据是如何存储的?
13 | 垃圾回收:垃圾数据是如何自动回收的?
14 | 编译器和解释器:V8是如何执行一段JavaScript代码的?
浏览器中的页面循环系统 (6讲)
15 | 消息队列和事件循环:页面是怎么“活”起来的?
16 | WebAPI:setTimeout是如何实现的?
17 | WebAPI:XMLHttpRequest是怎么实现的?
18 | 宏任务和微任务:不是所有任务都是一个待遇
19 | Promise:使用Promise,告别回调函数
20 | async/await:使用同步的方式去写异步代码
浏览器中的页面 (8讲)
21 | Chrome开发者工具:利用网络面板做性能分析
22 | DOM树:JavaScript是如何影响DOM树构建的?
23 | 渲染流水线:CSS如何影响首次加载时的白屏时间?
24 | 分层和合成机制:为什么CSS动画比JavaScript高效?
25 | 页面性能:如何系统地优化页面?
26 | 虚拟DOM:虚拟DOM和实际的DOM有何不同?
27 | 渐进式网页应用(PWA):它究竟解决了Web应用的哪些问题?
28 | WebComponent:像搭积木一样构建Web应用
浏览器中的网络 (3讲)
29 | HTTP/1:HTTP性能优化
30|HTTP/2:如何提升网络速度?
31|HTTP/3:甩掉TCP、TLS 的包袱,构建高效网络
浏览器安全 (5讲)
32 | 同源策略:为什么XMLHttpRequest不能跨域请求资源?
33 | 跨站脚本攻击(XSS):为什么Cookie中有HttpOnly属性?
34 | CSRF攻击:陌生链接不要随便点
35 | 安全沙箱:页面和系统之间的隔离墙
36 | HTTPS:让数据传输更安全
结束语 (1讲)
结束语 | 大道至简
课外加餐 (4讲)
加餐一|浏览上下文组:如何计算Chrome中渲染进程的个数?
加餐二|任务调度:有了setTimeOut,为什么还要使用rAF?
加餐三|加载阶段性能:使用Audits来优化Web性能
加餐四|页面性能工具:如何使用Performance?
浏览器工作原理与实践
登录|注册

06 | 渲染流程(下):HTML、CSS和JavaScript,是如何变成页面的?

李兵 2019-08-17
上篇文章中,我们介绍了渲染流水线中的 DOM 生成、样式计算布局三个阶段,那今天我们接着讲解渲染流水线后面的阶段。
这里还是先简单回顾下上节前三个阶段的主要内容:在 HTML 页面内容被提交给渲染引擎之后,渲染引擎首先将 HTML 解析为浏览器可以理解的 DOM;然后根据 CSS 样式表,计算出 DOM 树所有节点的样式;接着又计算每个元素的几何坐标位置,并将这些信息保存在布局树中。

分层

现在我们有了布局树,而且每个元素的具体位置信息都计算出来了,那么接下来是不是就要开始着手绘制页面了?
答案依然是否定的。
因为页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-indexing 做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。如果你熟悉 PS,相信你会很容易理解图层的概念,正是这些图层叠加在一起构成了最终的页面图像。
要想直观地理解什么是图层,你可以打开 Chrome 的“开发者工具”,选择“Layers”标签,就可以可视化页面的分层情况,如下图所示:
渲染引擎给页面多图层示意图
从上图可以看出,渲染引擎给页面分了很多图层,这些图层按照一定顺序叠加在一起,就形成了最终的页面,你可以参考下图:
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《浏览器工作原理与实践》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(59)

  • Hurry
    减少重排重绘, 方法很多:
    1. 使用 class 操作样式,而不是频繁操作 style
    2. 避免使用 table 布局
    3. 批量dom 操作,例如 createDocumentFragment,或者使用框架,例如 React
    4. Debounce window resize 事件
    5. 对 dom 属性的读写要分离
    6. will-change: transform 做优化

    作者回复: 总结的很好,很有经验👍

    2019-08-18
    2
    24
  • mfist
    减少重排重绘,相当于少了渲染进程的主线程和非主线程的很多计算和操作,能够加快web的展示。
    1 触发repaint reflow的操作尽量放在一起,比如改变dom高度和设置margin分开写,可能会出发两次重排
    2 通过虚拟dom层计算出操作总得差异,一起提交给浏览器。之前还用过createdocumentfragment来汇总append的dom,来减少触发重排重绘次数。

    作者回复: 很赞

    2019-08-17
    2
    20
  • 渲染进程里的帧的概念是什么样子的呢?一个page是一帧吗

    作者回复: 可以拿放电影电影来解释,通常,电影的帧速是24,也就是说每秒切换24幅画面,其中的每幅画面就是一帧。

    理解什么是帧后,我们在回过头看看我们的页面。由于目前大多数设备的屏幕刷新率为 60 次/秒。因此,如果页面中有一个动画、或一个渐变效果、或者用户正在滚动页面,那么浏览器渲染动画的频率至少要和刷新频率保持一致,也就是每秒需要更新60次,这样我们就能计算出来生成每帧的预算只有(1/60)毫秒,也就是16毫秒多一点(1 秒/ 60 = 16.66 毫秒)。如果超过16毫秒,帧率将下降,并且会出现画面抖动现象,此现象通常被称为卡顿,会对用户体验产生负面影响。



    所以,如果想要保证画面的流畅,就需要尽量降低每帧的渲染时间,所以局部更新流水线显得非常重要了,能大大减少处理每帧所消耗的时间。

    2019-08-17
    14
  • Luke
    关于浏览器渲染的知识点讲的很细致,我想问下,关于浏览器的渲染细节的知识老师是从哪里学到的?,是通过研究源码学习的吗?有没有一些好的学习资料或者学习方法推荐?能否专门出一篇“授人以渔”的文章,谢谢!

    作者回复: 主要几个途径:
    1:chromium源码
    2:chromium源码里面的一些注释和文档
    3:还有油管上blinkon上有一些深入讲解内核的视频


    目前基本没有系统介绍浏览器知识的文档,而且网上很多文档还是比较早期的,很多内容都不太适合新版的浏览器了。

    这里将浏览器知识和前端系统下结合起来是一件工作量非常大的事。

    2019-09-27
    7
  • ytd
    请教下老师,canvas的渲染流程是什么样的呢?它不涉及dom,也就不涉及dom树、样式计算、布局、分层,canvas的绘制过程也是在渲染进程中进行的吗?

    作者回复: canvas绘制流程很简单,就是调用api直接在画布上绘制,没有DOM,也没有太多套路!

    所有的绘制都是自己程序控制的

    2019-08-17
    2
    6
  • 杨陆伟
    最后的一段话非常经典,赞!大道至简,这真是做软件该秉持的原则,如果实现功能时感受到复杂和无序,那一定是那里错了

    作者回复: 说的好,如果感觉到复杂和无序,那一定是哪里错了

    2019-08-17
    5
  • 番茄
    最后一部分,合成和显示讲的太模糊的,不是很理解。
    2019-10-14
    3
  • 无名
    为何我的Layers标签中,选择了document,只有Details tab,没有Profile Tab?
    2019-08-27
    2
    3
  • 悬炫
    老师文中说需要剪裁(clip)的地方也会被创建为图层,但是我复制了老师的代码后,发现需要剪裁的地方并没有单独的被创建为图层,难道是最新版本的谷歌浏览器改了渲染规则?
    我的浏览器版本是 76.0.3809.100(正式版本) (64 位)
    2019-08-26
    2
    3
  • 老师,你好。
    关于把图层分块这块有些疑问,比如手机或者屏幕设备的尺寸并不总是256 * 256 或者 512 * 512 的整数倍。这样就会导致绘制的高度并不总是和内容刚好相等,表现为手机端有时候执行js拿到的html内容高度不对,不知道您遇到过没有?如果有,有没有一些好的实践获取内容高度呢,谢谢。
    2019-08-17
    2
  • tokey
    老师您好!
    我想问以下两个问题:
    问题1:手机端开发,body 被内容撑开了,超过一屏,在滑动的过程中会不会触发重排,为什么?
    问题2:如果 body 高度设置了100%

    作者回复: 现代浏览器做了优化,把滚动操作交给了合成线程来处理,也就是说滚动的内容会被当成一个单独的图层,发生滚动的事件的时候,图层直接由合成线程来生成,也就是说这种情况下没有占用主线程,所以通常情况下不会产生重排和重回操作,只是简单合成就可以了,这样效率是最高的!

    为什么说“通常”呢? 这是因为目前渲染流程还是很复杂的,在滚动页面时,有些情况下,如果合成线程搞不定的,那么还要交给主线程去处理,这时候就涉及到重拍了,不过技术是往前发展的,渲染流程会变得越来约简单高效!

    2019-08-17
    3
    2
  • splm
    在GPU进程完成栅格化,并把结果保存在GPU内存中,此时的结果仍然保存在独立进程中。那么从渲染进程的合成线程发送Drawquad命令到浏览器主线程调用Viz组件,主进程是在什么时候拿到之前存在GPU内存中的位图结果的?是Viz主动去GPU内存获取这部分结果进行合成的吗?这里没太看懂。
    2019-10-12
    1
  • 板栗
    老师,是将所有图块都栅格化,还是刚开始栅格化只可视区的图块,滚动的时候再去动态的栅格化。
    2019-09-18
    1
    1
  • Luke
    老师,你好,我有几个问题一直都很很困惑,也没找到答案,希望老师能解惑一下,感谢!
    1、图层、图块与BFC有什么区别联系吗?为什么BFC内元素的变动不会对BFC外的元素产生任何影响?是因为BFC会产生一个独立的图层或图块,渲染的时候只用重新渲染这一个图层或图块吗?BFC的原理是什么?
    2、在划分图层的时候,每个图层都会生成一系列的绘制指令,而在划分图块的时候,一个图块可能包含多个图层,一个图层也可能分成多个图块,那么在将图块绘制成位图的时候,是如何执行绘制指令的?需要将绘制指令再划分到不同的图块中吗?
    2019-09-10
    1
  • 帅气小熊猫
    这里的合成线程属于哪个进程?浏览器进程是指主进程吗?前面进程线程那块没有啊

    作者回复: 合成线程属于渲染进程,你可以看文中示意图!

    浏览器进程是主进程,负责提供一些基础服务和调度其它进程,你可以回顾下第一节和第四节内容。

    2019-08-19
    1
  • coder
    重排和回流有什么区别?
    2019-12-08
  • Geek_East
    渲染流程的最后,应该是浏览器进程将Compositor Frame发送到GPU, GPU进行显示吧?

    作者回复: 这块我没深入将了,因为结构比较复杂,chromium团队还在重构大的架构,既然你问到了,我就简要介绍下:

    1:首先渲染进程里执行图层合成(Layer Compositor),也就是生成图层的操作,具体地讲,渲染进程的合成线程接收到图层的绘制消息时,会通过光栅化线程池将其提交给GPU进程,在GPU进程中执行光栅化操作,执行完成,再将结果返回给渲染进程的合成线程,执行合成图层操作!

    2:合成的图层会被提交给浏览器进程,浏览器进程里会执行显示合成(Display Compositor),也就是将所有的图层合成为可以显示的页面图片。 最终显示器显示的就是浏览器进程中合成的页面图片

    2019-11-28
  • Geek_East
    有一个问题是:栅格化所有的图块,这里所有的是指页面全部的图块吗,还是只是viewport附近的图块;这个跟lazy-loading有什么关系吗?
    2019-11-28
  • 玉皇大亮
    知道原因了,很有趣,在OS X系统中,Chrome和其他App的分屏模式下,图层不显示,单独使用Chrome的情况下正常
    2019-11-22
  • 玉皇大亮
    老师,我在实现裁剪的例子中,在chrome浏览器下,并没有出现超出裁剪部分文字的专有图层,请问是什么原因呢?另外那段html代码div的width\height少了单位。
    2019-11-22
收起评论
59
返回
顶部