前端开发那些事儿

前端性能优化(中)

2020-08-20  本文已影响0人  9吧和9说9话
图片来自 昵图网

性能优化调研系列文章

  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

上一篇下一篇

猜你喜欢

热点阅读