前端性能优化(中)

图片来自 昵图网

性能优化调研系列文章

  1. 《前端性能优化(上)》
  2. 《前端性能优化(中)》
  3. 《前端性能优化(下)》

《前端性能优化(上)》 主要说明了:

  1. 为什么要进行前端性能优化?
  2. 如何衡量前端性能?

这一篇主要记录了浏览器的加载、渲染过程的调研结果和理解。(待详细梳理 提供动画版本)

浏览器加载、渲染过程

有一道经典的前端面试题: 从输入一个url到页面展示发生了什么? 涉及到计算机网络、操作系统、web等各个方面,从软件到硬件,从协议到实现,每一个点都可以展开深入的学习,所以很考察面试者的综合能力和某一个方面的深入掌握程度。

关于这部分知识,可以参考李兵老师的《浏览器原理》 课程介绍,下面的内容很大一部分 都是引用他的课程内容;另外《浏览器是如何工作的》也非常深入的介绍了浏览器工作的原理。

如果你想要有更深入的理解和掌握,建议你跟着大神一起来实现一个简单的浏览器引擎

image

不闻不若闻之 闻之不若见之 见之不若知之 知之不若行之 学至于行而止矣 -- 荀子

浏览器架构

浏览器渲染流水线
进程间通信
渲染主线程

浏览器导航

image

图片来源: 极客时间

  1. 浏览器主进程处理用户输入
  2. 浏览器主进程 通知网络进程 发起真正的请求
  3. 网络进程接收到请求头信息之后 发送给浏览器主进程
  4. 浏览器主进程 接收到网络进程发送的头消息之后 发送“提交导航 (CommitNavigation)”消息到渲染进程
  5. 渲染进程 收到“提交导航”消息之后,直接和网络进程建立数据管道,接受html数据
  6. 渲染进程接收html数据完成之后,会通知浏览器主进程:确认提交
  7. 主进程收到渲染进程的“确认提交”消息之后,就开始更新浏览器的状态:loading、前进、后退、url、当前页面
navigation timimg

以上 整个导航流程就走完了。

浏览器渲染流水线

一旦渲染进程发送 “确认提交”给浏览器主进程,就会开始解析页面加载子资源。

  1. html parsing


    图片来自google 文档- 解析html
  2. 生成DOM树


    图片来源 google文档- 生成DOM树
  3. 样式计算:Recaculate Style
    将样式信息(来自内联样式、style、link等)转换成styleSheets
    Recaculate Style 使用所有通过css parser解析得到的style rules,包括浏览器给出的默认样式,计算出每一个DOM元素最终的style的值,存储在ComputedStyle中。

图片来源 google文档- 样式计算
  1. 布局阶段: 生成LayoutTree
    经过样式计算阶段之后,DOM-Tree中的节点都有了自己的样式信息,但是还不知道如何排版,放到哪个位置。
    布局阶段,就是确定绘制区域的位置和大小,相对来说也是比较复杂。
    • 对于block flow布局来说相对简单,从上往下依次排列就好
      block flow
    • inline block


      inline-block
    • 其他更复杂的排版:文字、float、flex、table等等

总结来说,经过了布局阶段之后,就生成了一个LayoutTree

layout tree

  1. paint


    google文档-绘制
    • 我们已经通过布局阶段,得到了一棵LayoutTree,现在我们已经知道了每一个Layout object的布局、显示信息
    • 分层 生成图层数LayerTree:z-index、3D转换、 z-index 等会影响布局对象的显示顺序(层级)请参考 《层叠上下文》
      分层
    • 根据LayerTree,产出一个线性的绘制对象列表(列表中的每一个元素存放着绘制的显示对象和对应的绘制操作)
    • 对于单独的一个Layout Object,可能会包含多个显示对象(Display Item)(如果你使用过canvas 来绘制一些东西或者使用过一些游戏引擎对这个应该比较熟悉)

输出的display item list,会作为合成线程的输出

current display item list: [
  {
    "chunk": "LayoutBlockFlow DIV id='example' 
        0x1b94c141c0:LayoutBlockFlow DIV id='example':DrawingPaintPhaseSelfBlockBackgroundOnly:0",
    "state": "t:0x3e697bca90 c:0x3e697ac8d0 e:0x3e697ac290",
    "displayItems": [
      {
        "index": 0,
        "clientDebugName": "InlineTextBox 'hi'",
        "id": "0x1605c60410:InlineTextBox 'hi':DrawingPaintPhaseForeground:0",
        "visualRect": "401,357 72x20",
        "opaque": false,
        "record": [
          {
            "method": "drawTextBlob",
            "params": {
              "x": 401.5,
              "y": 373,
              "paint": {
                "color": "#FF333333",
                "strokeWidth": 0,
                "strokeMiter": 4,
                "flags": "AntiAlias",
                "filterLevel": "Low",
                "strokeCap": "Butt",
                "strokeJoin": "Miter",
                "styleName": "Fill"
              }
            }
          }
        ]
      }
    ]
  }
]


  1. 光栅化
    • 渲染主线程提交 绘制列表给 合成线程;
    • 合成线程将图层划分为图块(256256 或者 512512)
    • 合成线程将图块提交给 栅格化线程池
    • 渲染主进程 通过栅格化线程 发送图块生成位图的指令发送给GPU,
    • GPU 生成图块的位图,保存在GPU内存中
    • 一旦所有图块都被光栅化 合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程
    • 浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上

图片来源:极客时间

image

图片来源 google 文档

几个关于渲染流水线的问题

待补充示例demo

  1. CSS 外链下载会阻塞 DOM 的构建吗?
    不会, 参考demo
  1. CSS 外链下载会阻塞 布局树的构建吗?
    会 参考demo

  2. CSS外链文件下载会阻塞后面的js的下载吗?
    不会,现代浏览器会在收到html文档之后预解析,请求所有的资源


    image.png
  3. CSS外链文件下载会阻塞js的执行吗?


    css的下载阻塞了js的执行
  4. js文件的下载和执行会阻塞 DOM树的构建吗?

参考

  1. Let's build a browser engine!

  2. 《浏览器原理》

  3. 《浏览器是如何工作的》

  4. How Blink works

  5. life of pixel

  6. chrome university

  7. Inside a super fast CSS engine: Quantum CSS

你可能感兴趣的:(前端性能优化(中))