• 现代浏览器网页渲染原理简介


    为什么要理解浏览器的工作原理

    • 为了写出更好的代码和提供更好的用户体验

    浏览器是个多进程结构

    1. 浏览器进程:控制除标签页外的用户界面,包括地址,书签,后退,前进按钮等,以及负责与浏览器其他进程负责协调工作2.
    2. 缓存进程
    3. 网络进程 发起网络请求
    4. 渲染器进程 渲染Tab 有可能会为每个标签页是一个渲染进程
    5. GPU进程 渲染
    6. 插件进程 内置插件

    渲染进程的过程:

    1. 浏览器通过网络请求后获取html数据,通过tcp传给渲染器进程
    2. DOM - 主线程将html解析构造DOM树
    3. style - 样式计算
    4. layoutTree - dom+style 根据dom树和样式生成layoutTree
    5. paint -绘制 通过遍历 Layout Tree生成绘制顺序表
    6. laryer - 布局 然后根据主进程将layoutTree 和绘制信息表传给合成器线程
    7. 合成器线程 - 将得到的信息分图层分成更小的图块
    8. 栅格线程 - 将更小的图块进行栅格化raster,返还给合成器线程draw quads图块信息 存储在GPU中
    9. frame 合成器将栅格线程返回的图块合成帧交给浏览器进程
    10. 浏览器进程 收到一帧的图像后传给GPU进行渲染

    重排:
    当改变dom的属性时,会重新进行样式计算,会重新布局和绘制
    重绘:
    当改变颜色时,只会发生样式计算和绘制(layer)
    requestAnimationFrame()
    会将主线程的任务分散到每一帧的间隔,从而不影响动画的流程
    Fiber
    react利用浏览器的空闲时间做优化
    Transform
    会直接运行合成器线程,所以不会感染主线程的渲染
    在移动端使用3d转换可以优化性能(如果设备有3d加速引擎 GPU 可以提高性能 , 2d转换是无法调用GPU,2G是靠的CPU)

    1.前端层面输入一个地址然后按回车经历的过程

    (1)数据请求部分

     (2)数据处理部分

    (chrome)当网络线程获取到数据后,会通过SafeBrowsing(是谷歌内部的一套站点安全系统,通过检测该站点的数据是否安全,如看该IP是否在谷歌的黑名单内)来检查站点是否是恶意站点。如果是则显示警告页面,但还是可以继续访问。

    • 当返回数据下载完毕并且安全校验通过时,网络线程会通知UI线程已经准备好了,该你了。
    • UI线程会创建一个渲染器进程(Renderer Thread)来渲染页面
    • 浏览器进程通过IPC管道将数据传递给渲染器进程,进入渲染流程。渲染器进程的核心任务是把html,css,js,image等资源渲染成用户可以交互的web页面
    • 渲染器进程的主线程将html进行解析,构造DOM数据结构。
      1. html首先经过Tokeniser标记化,通过词法分析,将输入的html内容解析成多个标记,根据解析后的标记进行DOM树构造
      2. 在DOM树构造过程中会创建document对象,以document为根节点的DOM树不断修改,向其中添加各种元素。html代码中往往会引入其他资源,如图片、CSS、js等。图片和CSS资源需要通过网络下载或者从缓存中直接加载,这些资源不会阻塞html的解析,因为它们不会影响DOM的生成。但是当HTML解析过程中遇到script标签就会停止html解析流程,转而去加载解析并执行JS(因为JS可能会改变当前页面的HTML结构)。

      3. 在知道DOM节点和每个节点的样式后,接下来需要知道每个节点需要放到页面上的哪个位置(坐标及区域)。这个阶段称为Layout布局。主线程通过遍历dom和计算好的样式来生成Layout Tree。Layout Tree上的每个节点都记录了x,y坐标和边框尺寸。注意:
        1. Layout Tree和Dom tree并不是一一对应的
        2. 如设置了display:none。的节点不会出现在Layout tree 上,而在before伪类中添加了content值的元素,content里的内容会出现在Layout tree上,不会出现在DOM树里。这是因为DOM是通过HTML解析获得,并不关心样式。而layout tree是通过DOM树和计算好的样式来生成。layout tree是和最后展示在屏幕上的节点是对应的
    •  绘制(paint)
      • 我们需要知道以什么样的顺序绘制
      • 为了保证在屏幕上展示正确的层级。主线程遍历layout tree创建一个绘制记录表。该表记录了绘制的顺序这个阶段被称为绘制
    • 合成(Composting)
      • 知道了绘制顺序,可以把这些信息转化为像素点显示在屏幕上的时候了
      • 早期的chrome栅格化会导致展示延迟
      • 目前的处理方案是合成。合成是一种将页面上各个部分分成多个图层,分别对齐栅格化,并在合成器线程(Compositor Thread)中单独进行页面合成的技术。即:把页面所有的元素按照某种既定的规则进行分图层。并把图层都栅格化好了。然后只需要把可视区的内容组合成一帧展示给用户即可。

    汇总:

    • 浏览器进程中的网络线程请求获取到html数据后,通过IPC将数据传给渲染器进程的主线程
    • 主线程将html解析构造DOM树,然后进行样式计算。根据DOM树和生成好的样式生成Layout Tree
    • 通过遍历Layout Tree生成绘制顺序表,接着生成Layer tree。
    • 然后主线程将Layer Tree和绘制顺序信息一起传给合成器线程。
    • 合成器线程按规则进行分图层,并把图层分为更小的图块(tiles)传给栅格线程进行栅格化
    • 栅格化完成后,合成器线程会获得栅格线程传过来的"draw quads"图块信息
    • 根据这些信息,合成器线程上合成了一个合成器帧,然后将该合成器帧通过IPC传回给浏览器进程
    • 浏览器进程再传到GPU进行渲染。这样就展示到屏幕上了
    • 重排:当我们改变一个元素的尺寸位置属性时,会重新进行样式计算(Computed Style),布局(Layout)绘制(Paint)以及后面的所有流程
    • 重绘:当我们改变某个元素的颜色属性时,不会重新触发布局,但还是会触发样式计算和绘制。
    • 说明:
      1. 重排和重绘都会占用主线程,JS也会运行在主线程上,因此会出现抢占执行时间的问题
      2. 当页面以每秒60帧的刷新率才不会感觉到卡顿。如果在运行动画时还有大量的JS任务需要执行。因为布局、绘制和JS执行都是在主线程运行的
      3. 当在一帧的时间内布局和绘制结束后,还有剩余时间,JS就会拿到主线程的使用权,如果JS执行时间过长就会导致在下一帧开始时JS没有及时归还主线程,导致下一帧动画没有按时渲染,就会出现卡顿
      4. 处理:
      5. requestAnimationFrame()
      6. 使用Transfrom:通过Transform实现的动画不需要经过布局绘制、样式计算等操作。所以实现了很多运算时间

     (1)影响回流的操作

    • 添加/删除元素
    • 操作styles
    • display:none
    • offsetLeft,scrollTop,clientWidth
    • 移动元素的位置
    • 修改浏览器的大小,字体大小

     (2)避免layout thrashing——布局抖动

    回流的时候可能会出现layout thrashing问题:因为强制不断的回流的发生

    • 避免回流
      • CSS方面:如用translate实现位移等
      • 减少回流:如React的virtual DOM减少回流的发生
    • 读写分离
  • 相关阅读:
    JDK中的主要包
    package

    参数传值机制
    静态初始化块
    static 关键字
    this关键字
    开发中容易造成内存泄露的操作
    通用的分代垃圾回收机制
    JVM调优和Full GC
  • 原文地址:https://www.cnblogs.com/codexlx/p/13993356.html
Copyright © 2020-2023  润新知