浏览器原理与实现-学习1-线程与进程/tcp/http/导航流程/渲染流程

279 阅读13分钟

1.线程与进程

进程

  • 一个进程是一个程序的实例
  • 进程统一管理和启动线程
  • 一个进程包含一个或多个线程
  • 浏览器1个页面4个进程
  • 进程之间互相独立,通过IPC通讯

线程

  • 多个线程可以实现并行处理
  • 线程不能独立存在,依付于进程
  • 线程共享进程里的数据
  • 单个线程异常会导致整个进程挂掉

早期单线程浏览器

  • 缺点
    • 在页面线程上有长任务会卡死,不稳定
    • 插件可以访问系统资源,不安全
    • 由于都在一个进程里,如果内存没有正常释放,会越堆越多
  • 组成
    • 其他线程
    • 网络线程
    • 页面线程
      • js环境
      • 页面渲染
      • 页面展示
      • 插件

2008多进程浏览器时代

  • 组成
    • 浏览器进程
      • 下载资源
      • 管理IPC
      • 显示渲染进程生产的图片
    • 渲染进程
      • 解析
      • 渲染
      • js执行
      • 合成网页图片
    • 插件进程
  • 优点
    • 稳定
      • 插件独立进程,奔溃不影响页面
    • 流畅
      • 多个tab页面多个独立进程渲染进程,不互相影响运行
      • 内存泄漏不再存在,因为进程关闭,所有进程对应的所有资源都会回收
    • 安全
      • 渲染进程在独立沙盒,不能访问系统资源

现代的多进程浏览器架构

多个tab页面就有多个渲染进程,网络进程和 GPU进程UI绘制独立出来。

  • 浏览器进程
    • 显示
    • 用户交互
    • 子进程管理
    • 储存
  • 渲染进程
    • html css解析处理的排版引擎Blink 线程
    • 执行js的 V8引擎,线程
    • 在沙盒里
    • 一个tab页签一个渲染进程
  • 插件进程
  • 网络进程
  • GPU进程
    • UI界面采用GPU绘制

缺点

  • 资源占用更多
    • 进程的数量多,对于某些移动设备加载了无用的模块
  • 系统架构复杂
    • 各个模块互相依赖,强耦合

未来浏览器架构

面向微服务 : 构建一个更内聚、松耦合、易于维护和扩展的系统。

  • 组成
    • 浏览器主进程 :
      • 微服务
        • UI进程
        • 文件进程
        • 音频进程
        • GPU进程
        • 网络进程
    • 渲染进程
    • 插件进程

当资源不足,如移动设备 按把上面的微服务进程 改成service需合并到浏览器主进程

优点

  • 资源占用更小
    • 进程的数量更少了,按需加载
  • 系统架构根据简单
    • 各个模块解构,互相不再强依赖

2. tcp/udp/ip协议

协议是一套众所周知的规则和标准,大家跟根据规则和约定传输数据

IP协议

  • Internet Protocol
  • IP地址
  • 发出方  应用层->网络层  数据+IP头传输 -> 物理层
  • 接收方 物理层-> 网络层 数据+解析IP头判断对应的主机->应用层

UDP协议

  • User Data Protocol
  • 比IP协议多包一个端口,区分是哪个应用
  • 发出方  应用层->传输层   UDP头   -> 网络层  数据+IP头传输 -> 物理层
  • 接收方. 物理层 -> 网络层 数据+解析IP头判断对应的主机. ->. 传输层.解析UDP头  ->应用层
  • 优点
    • 传输快
  • 缺点
    • 容易丢失
    • 不完整

TCP协议

transmission control Protocol 传输控制协议,传输逻辑与 UDP一致,UDP头改TCP头。 是一种面向连接的、可靠的、基于字节流的传输层通信协议。

生命周期

  1. 建立连接
    • 3次握手,客户端与服务端确认身份
  2. 数据传输
    • 每一次客户端接收数据,都是发送给服务器,确认已经收到,当规定时间内未收到确认信息,服务器会重新发送该包
    • 大文件会拆成多个小文件,会跟句tcp头的序号排列顺序重新组装
  3. 断开连接
    • 4次挥手

总结

  • 互联网通过大文件拆成多个包传输,但是包容易丢失
  • IP发送数据
  • UDP发送给对应应用数据
  • TCP通过3个阶段,建立连接,发送数据,断开连接,确保了对应应用数据的接收的可靠与完整性

3.http协议/请求流程

整体流程分为:客户端请求,服务端响应,客户端处理响应

image.png

image.png

image.png

3.1.客户端发起的流程

  1. 构建请求 - 构建请求行信息,转化为GET www.baidu.com/index.html HTTP1.1
  2. 查找本地缓存 - 强缓存 - 当缓存数据满足条件时,直接返回,无需再走下面流程
  3. DNS解析,通过Domain Name System DNS系统-获取IP - 读取本地浏览器DNS缓存 - 访问系统host配置 - 访问互联网DNS服务器
  4. 等待TCP队列 - 同个域名只能有6个TCP进行中的请求
  5. 建立TCP连接 - 3次握手
  6. 发送HTTP内容
    • GET情况
      • 请求行
        • 请求方法
        • 请求URI地址
        • 请求http版本
            GET 192.168.0.xx/index.html HTTP1.1  # 请求方法 请求URI地址 请求http版本
        
    • POST情况
      • 请求行
      • 请求头:浏览器信息
      • 请求体:数据内容
          POST 192.168.0.xx/api HTTP1.1  # 请求行 
          #---------  请求头
          authority: juejin.cn  
          method: GET 
          scheme: https
          accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
          accept-encoding: gzip, deflate, br
          accept-language: zh-CN,zh;q=0.9,ru;q=0.8,zh-TW;q=0.7
          cache-control: no-cache 
          pragma: no-cache 
          user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
          #---------请求头
      
          #---------  请求体
          [a:1,b:2]
          #---------  请求体
      

3.2.服务器回复的流程

  1. 服务器接收信息
  2. 服务器返回HTTP内容
    • 返回响应行,响应头,响应体
  3. TCP连接断开
    • 如果没有keep-alive标识,4次挥手

3.3.客户端处理响应

  1. 客户端接受消息
    • 包含响应行,响应头,响应体
  2. 客户端断开连接
    • 如果没有keep-alive标识,4次挥手
  3. 内容处理
    • 重定向:当服务端 返回301,并且 响应体 包含location信息,浏览器拿到后会自己重定向
    • 如果是下载流,调用网络进程下载
    • 如果是html 开始渲染流程

3.3.用户登录状态实现

  • 服务返回 响应头 Set-Cookie: UID=abcds
  • 客户端后续请求,请求头 自动带上 Cookie: UID=abcds
  • 服务器读取 Cookie: UID确认身份

4.导航流程

导航流程主要包含 浏览器进程,网络进程,渲染进程,三块进行。

  1. 浏览器发起url
  2. 网络进程处理请求,并读取响应头和体信息
  3. 网络进程读完响应头信息,就可以开始通知浏览器进程生成渲染进程,同时浏览器也更新当前tab页签状态与内容清空
  4. 渲染进程开始解析,不断读取响应体信息
  5. 当所有资源已加载并解析完成后,通知浏览器进程加载完成。

注意:提交的文档指的是 :响应体数据

image.png

进程结构与作用

  • 浏览器进程
    • 用户交互
    • 子进程管理,IPC通讯
    • 文件处理
    • 图形显示
  • 网络进程
  • 渲染进程
    • html css js 转化为 显示和交互的页面

导航流程

1. 地址栏输入url

地址栏会判断输入的关键字是搜索内容,还是请求的 URL。

  • 搜索内容转化成带参数的搜索url地址
  • url地址则直接进入页面请求过程

注意:当前web页面内容不清除,需要等到提交文档阶段才刷新

2. 网络进程发起请求

浏览器进程通过IPC通知 网络进程发起网络请求

  1. 判断本地缓存
  2. DNS解析ip
  3. 建立TCP(https包含TLS处理)
  4. 服务器处理并返回数据
  5. 客户端处理
    1. 重定向
    2. 判断数据类型
      • 如果是: text/html继续导航流程
      • 如果是: application/octet-stream 交给下载管理器

3. 浏览器 实例化渲染进程

共用一个进程的情况

  • 满足条件1: 同一站点:根域名+ 协议 ,如http:www.baidu.com, map.baidu.com:8081 
  • 满足条件2:并且如果从一个页面打开了另一个新页面

4. 提交文档

渲染进程实例化后,向渲染进程提交页面数据

  1. 统一由浏览器进程 通知网络进程吧数据提交给 渲染进程。两者建立管道
  2. 传输完后,渲染进程告诉浏览器进程:确认提交
  3. 浏览器进程收到确认提交后,更新浏览器页面内容,包括地址栏url,前进后退,更新web页面

注意:

  1. 由于渲染进程解析的内容都是网络获取,所以浏览器默认认为是不安全的。所以把渲染进程放在安全沙箱里。没有权限直接操作浏览器进程相关内容,只能通过IPC调用。
  2. 提交的文档不是加载完才提交,而是边读取边提交

5. 渲染进程接收完文档

开始解析与加载子资源,完成页面渲染

  • 停止小icon转圈

5.渲染流水线

执行过程

  • 多个子阶段
  • 每个子阶段都有3个过程
    • 输入内容

    • 处理内容

    • 输出内容

3种输入来源

  • HTML
    • 超文本协议
    • 标签+文本
  • CSS
    • 层叠样式
    • 选择器+属性
  • JS
    • JavaScript
    • 动态脚本

9个阶段 

image.png

1. 构建dom树

  • 输入html
  • 解析html
  • 输出AST dom树

2. 样式计算 style(Recalculate style)

把dom + sheetstyles集合 合并成 渲染树(render tree)

注意: sheetstyles 可以等价理解为 cssom
  1. 把 CSS 转换为浏览器能够理解的结构
    • 输入3种 link , <style> </style>, <p style>
    • 输出document.sheetstyles集合,即cssom
  2. 样式属性值标准化,如
    • 2em -> 32px,red -> rgb(255,0,0),bold -> 700
  3. 计算dom中每个节点的具体样式
    • 每一个dom节点都会生成 ComputedStyle对象记录样式
    • 继承规则
      • UserAgent系统默认样式
      • 自上而下的继承样式如body的font-szie 会一直往里继承
      • 继承关系 Useragent -> html -> body -> div -> p -> span
    • 层叠规则
      • 通过层叠样式表叠加(css 全称 层叠样式表 也来源)

3. 布局 layout

布局:创建布局的可见元素的几何位置,这个过程会生成布局树,layout tree

  1. 创建可见布局树
    • 忽略dispaly:none
  2. 布局计算
    • 布局节点的相关坐标 过程是否复杂耗时
    • 布局运算的结果会重新回写到布局树
    • 即是输入也是输出

4. 分层 layer

渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树 layer tree

  • 生成图层树
    • 不是所有布局树节点都对应一个图层
    • 满足独立生成图片的条件,拥有层叠上下文的属性
      • postion:fixed
      • z-index:1
      • filter:blue(1px)
      • opacity:0.3
    • 要用于裁剪的地方
      • overflow 小的div里放了很多内容 出现
        • 小DIV内的内容就会单独生成图层
        • 滚动条会单独生成图层

5. 生成绘制指令列表 paint

  • 把多个图层生成多个绘制指令列表
  • 指令:操作:绘制圆形坐标:xxx样式:xxxx 注意:这里只是生成指令没有真正绘制图片

6. 分块 tiles

由于每个分层画的内容可能远远超过用户视口可以显示的大小。 为了优化减少渲染的面积,会把一张大图切割成多个小图块,最终根据视口区域渲染指定的小图块渲染。

注意:此时依然为开始渲染图片,只是把每一个layer图层指令再细化精简成绘制图块指令。

image.png

如上图所示,浏览器只会拿图块 3,4,5,6,7,8 做渲染,其他都不处理。

  • 主线程提交 绘制指令列表 给 合成线程
  • 合成线程把大的图层分成一各个小块的图块
    • 512*512 或者 256*256
  • 图块是光栅化执行的最小单位
  • 概念
    • 视口viewport:当前窗口最大的显示区域
    • 可见图块 visible tiles
    • 图块 tile
    • 图层 layer

7. 光栅化 raster

把上面生成的图块指令通过栅格化,生成一张适合视口大小显示的图片。

  • 图块栅格:合成线程根据当前视口所包含的图块都统一渲染为位图
  • 栅格化:将图块转化为位图

优化特点

  • 通过只渲染视口的内容,实现优化渲染的速度
  • 栅格化的线程池
    • 图块栅格化都在这里执行
    • 包含多个栅格的线程
  • 使用GPU加速,把线程池的内容提交给 GPU进程处理,生成的图片保存在GPU中

8. 合成 drawquad

  1. 当所有图块都被光栅化后,合成进程生成绘图指令 DarwQuad 提交给浏览器进程

9.显示 display

  1. 浏览器进程使用 viz 的组件 将内容绘制到 内存中
  2. 最终把内存信息显示到屏幕

完整流程

  1. 渲染进程将 HTML 内容转换为能够读懂的DOM 树结构。
  2. 渲染引擎将 CSS 样式表转化为浏览器可以理解的styleSheets,计算出 DOM 节点的样式。
  3. 创建布局树,并计算元素的布局信息。
  4. 对布局树进行分层,并生成分层树。
  5. 为每个图层生成绘制列表指令,并将其提交到合成线程。
  6. 合成线程将图层指令分成图块指令
  7. 合成线程根据当前视口所包含的图块指令都统一栅格渲染为位图。
  8. 合成线程把渲染后的位图发送绘制图块命令DrawQuad给浏览器进程。
  9. 浏览器进程根据 DrawQuad 消息生成页面,加载到内存,并显示到显示器上。

渲染中的主线程与非主线程关系

  • 主线程(阻塞)
    • dom树
    • style样式计算
    • 布局
    • 分层
    • 生成绘制指令
  • 非主线程(非阻塞)
    • 合成线程
      • 分块
      • 生成位图
    • GPU进程 :光栅,并且通过drawquad通知 浏览器进程
    • 浏览器进程 :display显示

image.png

重排,重绘,合成

重排

  • 元素几何属性变化
  • 触发dom以外的完整的渲染流程(从style样式计算开始)
el.style.width = '30px'; 

当前宽度变化,发生几何变化,会从样式计算开始重新走一遍渲染流程

image.png

重绘

  • 绘制属性变化
  • 跳过了 布局和分层阶段 (从style样式计算开始)
el.style.backgroundColor = 'red'; 

当前背景色发生变化,几何信息没有变动会,会从样式计算开始,中间跳过 layout和layer两个阶段。

因为layout为了计算坐标和显示节点,layer是为了特殊节点如 z-index分层。这些重绘时都没有影响到。

image.png

直接合成

  • 直接通过css中的transform 改变样式,会跳过 布局 ,分层 ,生成绘制指令阶段,性能更优 (从style样式计算开始)
el.style.transform = 'scaleX(0.8)';  //x方向 压缩为0.8

由于transform 使用的是gpu独立的渲染进程处理,从样式计算,后面的布局 ,分层 ,生成绘制指令阶段都无需执行,直接到分块继续。

image.png

参考

time.geekbang.org/column/intr…