浏览器工作原理与实践
李兵
前盛大创新院高级研究员
立即订阅
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?
浏览器工作原理与实践
登录|注册

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

李兵 2019-08-15
上一篇文章中我们介绍了导航相关的流程,那导航被提交后又会怎么样呢?就进入了渲染阶段。这个阶段很重要,了解其相关流程能让你“看透”页面是如何工作的,有了这些知识,你可以解决一系列相关的问题,比如能熟练使用开发者工具,因为能够理解开发者工具里面大部分项目的含义,能优化页面卡顿问题,使用 JavaScript 优化动画流程,通过优化样式表来防止强制同步布局,等等。
既然它的功能这么强大,那么今天,我们就来好好聊聊渲染流程
通常,我们编写好 HTML、CSS、JavaScript 等文件,经过浏览器就会显示出漂亮的页面(如下图所示),但是你知道它们是如何转化成页面的吗?这背后的原理,估计很多人都答不上来。
渲染流程示意图
从图中可以看出,左边输入的是 HTML、CSS、JavaScript 数据,这些数据经过中间渲染模块的处理,最终输出为屏幕上的像素。
这中间的渲染模块就是我们今天要讨论的主题。为了能更好地理解下文,你可以先结合下图快速抓住 HTML、CSS 和 JavaScript 的含义:
HTML、CSS 和 JavaScript 关系图
从上图可以看出,HTML 的内容是由标记和文本组成。标记也称为标签,每个标签都有它自己的语意,浏览器会根据标签的语意来正确展示 HTML 内容。比如上面的<p>标签是告诉浏览器在这里的内容需要创建一个新段落,中间的文本就是段落中需要显示的内容。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《浏览器工作原理与实践》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(37)

  • mfist
    关于下载css文件阻塞的问题,我理解
    1 不会阻塞dom树的构建,原因Html转化为dom树的过程,发现文件请求会交给网络进程去请求对应文件,渲染进程继续解析Html。
    2 会阻塞页面的显示,当计算样式的时候需要等待css文件的资源进行层叠样式。资源阻塞了,会进行等待,直到网络超时,network直接报出相应错误,渲染进程继续层叠样式计算

    作者回复: 借这里解答下留的题目:

    当从服务器接收HTML页面的第一批数据时,DOM解析器就开始工作了,在解析过程中,如果遇到了JS脚本,如下所示:
    <html>
        <body>
            极客时间
            <script>
            document.write("--foo")
            </script>
        </body>
    </html>
    那么DOM解析器会先执行JavaScript脚本,执行完成之后,再继续往下解析。

    那么第二种情况复杂点了,我们内联的脚本替换成js外部文件,如下所示:
    <html>
        <body>
            极客时间
            <script type="text/javascript" src="foo.js"></script>
        </body>
    </html>
    这种情况下,当解析到JavaScript的时候,会先暂停DOM解析,并下载foo.js文件,下载完成之后执行该段JS文件,然后再继续往下解析DOM。这就是JavaScript文件为什么会阻塞DOM渲染。

    我们再看第三种情况,还是看下面代码:
    <html>
        <head>
            <style type="text/css" src = "theme.css" />
        </head>
        <body>
            <p>极客时间</p>
            <script>
                let e = document.getElementsByTagName('p')[0]
                e.style.color = 'blue'
            </script>
        </body>
    </html>
    当我在JavaScript中访问了某个元素的样式,那么这时候就需要等待这个样式被下载完成才能继续往下执行,所以在这种情况下,CSS也会阻塞DOM的解析。


    所以JS和CSS都有可能会阻塞DOM解析,关于详细信息我们会在后面的章节中详细介绍。

    2019-08-15
    3
    57
  • Angus
    这节讲的有些过于省略了,好多东西没有深入去讲。我记得是DOM树和CSSOM树并行构建合成渲染树。从这个角度来说,不会阻塞DOM树的构建,但是会阻塞页面显示,因为页面显示需要完整的渲染树去完成布局计算。

    作者回复: 和DOM不一样,在源码里面并没有CSSOM这个词,你说的CSSOM 应该是就是styleSheets,这个styleSheets是能直观感受的到的。

    渲染树也是16年之前的东西了,现在的代码完全重构了,你可以把LayoutTree看成是渲染树,不过和之前的渲染树还是有一些差别的。

    2019-08-15
    24
  • Been
    老师,渲染进程的工作原理您是从哪知道的,看浏览器的源码吗? 有链接吗来一个

    作者回复: 这个链接有一些参考资料你可以参考下:https://time.geekbang.org/column/article/116572

    2019-08-15
    7
  • William
    请问老师,为什么没有清晰地将输入内容和输出内容区分开来不好,我们平时编码过程中,应该尽量做到将输入内容和输出内容区分开来吗?

    作者回复: 分开来,结构会更加清晰,目前布局操作都是在主线程执行执行的,如果将布局的输入结构和输出结构分开来,那么可以在另外一个线程上执行布局操作,解析完把结果提交给主线程,这样会减轻主线程的压力。

    所将输入结构和输出结构分开,后续就可以更好地重构渲染模块的代码了!

    这也是Chrome渲染团队目前在做的一件事。

    2019-08-15
    2
    7
  • 袋袋
    不阻塞dom合成,也不阻塞页面渲染,页面还是会生成,只不过没有样式而已,别忘了标签是有语义化的
    2019-08-15
    4
  • Aaaaaaaaaaayou
    css继承中应该不是所有的属性都会继承吧
    2019-08-20
    1
    3
  • 安追
    我打开chrome面板的performance,记录了页面的加载过程。想请教一个问题。
    首先确认一下几个概念:
    1. recalculatestyle过程是指生成computedStyle过程吗?
    2. DOMContentLoaded事件标识浏览器已经完全加载了 HTML,DOM 树已经构建完毕。
    我发现在DOMContentLoaded之前,生成computedStyle和构建DOM的过程是并行的。我之前的想法是,计算DOM节点的样式(computedStyle)的前置条件是构建DOM、CSS生成StyleSheets并完成属性值标准化,这样才能保证DOM节点样式的计算有条不紊。我的问题是:浏览器是如何并行处理构建DOM、生成computedStyle的流程的?
    2019-08-16
    3
  • William
    思考题。不会,CSS阻塞了,DOM树照样能正常解析和渲染。猜测浏览器机制,会优先渲染DOM到页面上。平时网络不好时遇到过。
    2019-08-15
    3
  • 许童童
    如果下载 CSS 文件阻塞了,会阻塞 DOM 树的合成吗?会阻塞页面的显示吗?
    不会阻塞DOM 树的合成,但会阻塞页面的显示。
    DOM 树和CSSOM树是并行生成的,两个都完成后才进行布局树的生成,但如果期间有JS文件,那就需要等待JS文件加载并执行完成,JS也需要等待CSSOM树生成,因为JS可能操作DOM树和CSSOM树。
    2019-08-15
    2
  • 悬炫

    DOM树的构建和样式计算都是在渲染进程的主线程上执行的,他们可以并行执行吗?如果可以的话,那他们是如何来实现并行的呢?是通过异步回调还是说用的是类似于Generator函数的协程呢?在css会阻塞dom树的构建的情况下,主线程是如何去暂停DOM树的构建,后期又是如何恢复DOM树的构建的呢?希望老师解答一下
    2019-08-28
    1
  • 海骅薯条
    下载CSS文件阻塞了,原则上会阻塞页面的显示,但是浏览器可以有自己的容错机制,例如下载超时后,均采用user-agent stylesheet 默认样式进行渲染就可以啦,虽然丑点,但是内容在HTML都显示出来啦
    2019-08-20
    1
  • 匡晨辉
    老师,如果一个页面有很多个外联css文件,是需要把所有的css文件全部下载完毕后才能生成computeStyle 还是是个持续过程,下载一个css就更新computeStyle?如果是前者的话,也就是说css加载完毕前,页面是空白的,但实际流量网页有这种现象:开始显示的没有样式的页面,过了一段时间就好了,这就矛盾了;但如果是后者的话,那咱们生成computestyle的过程中可能有更新的操作,从老师您的课程中并没有体现,具体机制到底是怎么样的,老师能不能帮忙解答一下?
    2019-12-04
  • -_-_aaa
    渲染进程有几个线程,执行到js代码时主线程是到了V8引擎那了吗?并且V8引擎有时还会等CSS代码下载完才会继续解析下面的js代码?
    2019-12-02
  • 王二柱
    请问“DOM 是保存在内存中树状结构,可以通过 JavaScript 来查询或修改其内容”,既然DOM树已经保存在内存中并且可以通过JS查询,为什么有的框架还需要建立一个虚拟DOM树呢,岂不是占用了更多的内存
    2019-10-17
  • why.
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <title>css阻塞</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
          h1 {
            color: red !important
          }
        </style>
        <script>
          function h () {
            
            console.log(document.querySelectorAll('h1'))
          }
          h()
        </script>
        <link href="https://github.githubassets.com/assets/site-d20aa35917cf810095fab7458ea2a8e4.css" rel="stylesheet">
      </head>
      <body>
        <h1>这是红色的</h1>
        <script>
          console.log('hello world')
        </script>
      </body>
    </html>
    未等css样式加载完成,上述log 已经打印出了h1结点 (那可以理解成css不会阻塞dom解析吧);body 里面添加js脚本,是需要等待css样式加载完成之后才能执行
    2019-09-28
  • GY
    请问下老师,BFC这个过程,是发生在布局阶段吗?
    2019-09-23
  • 杨学茂
    解析css的时机是什么?如果将style和link标签放在最后,我们会先看到一版默认样式,这种情况下css阻塞合成与渲染了吗?
    2019-09-06
  • Kyeon
    老师好,当渲染进程接收到html文档之后,它先顺序解析这篇文档。假设这篇文档的head标签中外联了css文件,那么DOM解析器暂停DOM解析,等待网络进程下载css文件之后浏览器进程提交给渲染进程该css文件,收到文件后继续DOM解析,开始解析css文件。那么,请问解析这个css文件的流程是不是就是文章中的三步:1. 转换css结构 2. 标准化属性值 3. 计算DOM节点样式 ?如果流程是这样的的话,是不是说渲染阶段中包含的这些子阶段其实并不是一级一级顺序执行的? 谢谢
    2019-09-05
  • 空山鸟语
    css选择器优先级怎么评定?
    每个选择器是有一个固定的值吗?
    比如
     #idname {}
    .classname.active {}
    这两个选择器匹配到同一个dom的时候,二者的优先级哪个高?
    2019-09-05
    3
  • Cris
    js css阻塞dom解析是不是会表现为页面白屏?
    2019-09-03
收起评论
37
返回
顶部