小宋爱睡觉 小宋爱睡觉
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
  • 网络攻击与防范
  • 进程和线程
  • 浏览器缓存
  • 浏览器的存储
  • 浏览器的渲染原理
    • 简述一下浏览器的渲染过程
    • 介绍一下浏览器的渲染优化
    • 渲染过程中遇到的js文件如何处理
    • 什么是文档的预解析
    • CSS如何阻塞文档解析
    • js脚本放在头部一定会造成阻塞吗
    • 如何优化关键渲染路径
    • 什么情况下会阻塞渲染
  • 浏览器的同源策略
  • 浏览器的事件循环
  • 浏览器的垃圾回收机制
  • 浏览器组成
  • 浏览器原理
Crucials
2021-12-13

浏览器的渲染原理

# 浏览器的渲染原理

# 简述一下浏览器的渲染过程重要

  • 首先解析收到的文档,根据文档的定义构建一棵DOM树,DOM树是由DOM元素及属性节点组成的

  • 然后对css进行解析,生成CSSOM树

  • 根据DOM树和CSSOM树构建render树,渲染树的节点被称为渲染对象,渲染对象是一个包含有颜色和大小等属性的矩形,渲染对象和DOM元素相对应,但是不可见的DOM元素不会被插入render树上,还有一个dom元素对应几个可见对象,是一些具有复杂结构的元素,无法用矩形来描述

  • 当渲染对象被创建并添加到树中,他们没有位置和大小,所以当浏览器生成render树之后,会根据render树进行布局(也可以叫回流),此时浏览器要弄清楚各个节点在页面的确切位置和大小,也被称为自动重排

  • 布局结束后是绘制阶段,遍历渲染树并调用渲染对象的paint方法将内容显示在屏幕上,绘制使用UI基础组件

img

注意

这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html 都解析完成之后再去构建和布局 render 树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容

# 介绍一下浏览器的渲染优化

  • 针对JS:js会阻塞html解析,也会阻塞css解析

    • 尽量将js文件放在body最后
    • body中间尽量不要写script标签
    • script的三种引入方式
      • <script> 立即停止页面渲染去加载资源文件,当资源加载完毕后立即执行js代码,js代码执行完毕后继续渲染页面;
      • async 是在下载完成之后,立即异步加载,加载好后立即执行,多个带async属性的标签,不能保证加载的顺序;
      • defer 是在下载完成之后,立即异步加载。加载好后,如果 DOM 树还没构建好,则先等 DOM 树解析好再执行;如果DOM树已经准备好,则立即执行。多个带defer属性的标签,按照顺序执行。
  • 针对CSS:使用css的方法:link @import 内联样式

    • link:浏览器会派发一个线程(http线程)去加载资源文件,同时GUI渲染线程会继续向下渲染代码

    • @import:GUI渲染线程会暂停渲染,去服务器加载资源文件,资源文件没返回之前不会继续渲染(阻碍浏览器渲染)

    • 内联样式:GUI线程直接渲染

      注意⚠️

      外部样式如果长时间没有加载完毕,浏览器为了用户体验,会使用浏览器会默认样式,确保首次渲染的速度。所以CSS一般写在header中,让浏览器尽快发送请求去获取css样式。所以,在开发过程中,导入外部样式使用link,而不用@import。如果css少,尽可能采用内嵌样式,直接写在style标签中

  • 针对DOM树 CSSOM树

    • html文件代码层级尽量不要太深
    • 使用语义化标签,避免不标准语义化的特殊处理
    • 减少css代码的层级,因为选择器是从右向左进行解析的
  • 减少回流和重绘

    • 操作dom时,尽量在底层级的dom节点进行操作
    • 不要使用table,一个小的改动会使整个table进行重新布局
    • 不能频繁操作元素的样式,对于静态页面,尽量修改类名,而不是样式
    • 使用css表达式
    • 使用absolute或者fixed,使元素脱离文档流,这样发生变化不会影响其他元素
    • 避免频繁操作dom,可以创建一个文档片段,documentFragment,在他上面应用所有dom操作,然后把他添加到文档中
    • 将元素先display:none,操作结束后再把他显示出来,因为display为none中进行dom操作不会引发回流和重绘
    • 将dom的多个读写操作放在一个,而不是读写操作穿插,得益于浏览器的渲染队列机制

    值得注意的是⚠️

    浏览器会将所有的回流、重绘的操作放在一个队列中,当队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会对队列进行批处理。这样就会让多次的回流、重绘变成一次回流重绘。 将多个读操作(或者写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,原本应该是触发多次回流,变成了只触发一次回流。

# 渲染过程中遇到的js文件如何处理

js的加载、解析和执行会阻塞文档的解析,也就是说在构建dom是,html解析器遇到js的话会暂停文档的解析,然后将控制权移交给JS引擎,等他完成之后浏览器再从中断等地方恢复继续解析文档,也就是说,如果想要首屏渲染地越快,就越不应该再首屏加载JS文件,还是建议把script放到body的底部,或者加上defer或async

# 什么是文档的预解析

webkit和firefox都做了优化,当执行JS脚本的时候,另一个线程解析剩下的文档并加载后面需要用到的网络资源,这种方式可以使资源并行加载从而使整体速度更快,值得注意的是预解析并不改变dom树,他将整个工作留给了主解析过程,自己只解析外部资源的引用,比如外部script、css、image

# CSS如何阻塞文档解析

理论上即使css不改变dom树,也就没有必要停下文档的解析等待他们,然而当JS执行时可能在文档解析过程中请求样式信息,如果样式还没有加载和解析,脚本将得到错误的值,显然会导致很多问题,所以如果浏览器尚未完成 CSSOM 的下载和构建,而我们却想在此时运行脚本,那么浏览器将延迟 JavaScript 脚本执行和文档的解析,直至其完成 CSSOM 的下载和构建。也就是说,在这种情况下,浏览器会先下载和构建 CSSOM,然后再执行 JavaScript,最后再继续文档的解析

# js脚本放在头部一定会造成阻塞吗

不一定会

如果js并没有引用dom的话就不会造成阻塞,当然也不排除其他情况阻塞,但是并不会一定造成阻塞

# 如何优化关键渲染路径

为了尽快完成首次渲染,需要最大限度减小以下三种可变因素

  • 关键资源的数量

  • 关键路径长度

  • 关键字节的数量

关键资源是可能阻止网页首次渲染的资源。

这些资源越少,浏览器的工作量就越小,对 CPU 以及其他资源的占用也就越少。同样,关键路径长度受所有关键资源与其字节大小之间依赖关系图的影响:某些资源只能在上一资源处理完毕之后才能开始下载,并且资源越大,下载所需的往返次数就越多。

最后,浏览器需要下载的关键字节越少,处理内容并让其出现在屏幕上的速度就越快。要减少字节数,我们可以减少资源数(将它们删除或设为非关键资源),此外还要压缩和优化各项资源,确保最大限度减小传送大小。

优化关键渲染路径的常规步骤如下:

  1. 对关键路径进行分析和特性描述:资源数、字节数、长度。
  2. 最大限度减少关键资源的数量:删除它们,延迟它们的下载,将它们标记为异步等。
  3. 优化关键字节数以缩短下载时间(往返次数)。
  4. 优化其余关键资源的加载顺序:您需要尽早下载所有关键资源,以缩短关键路径长度

# 什么情况下会阻塞渲染

首先渲染的前提是生成render树,所以html和css肯定会阻止渲染,如果想更快,那只能降低文件大小或者压缩,扁平层级,优化选择器。然后当浏览器解析到script标签时,会暂停构建DOM,完成之后才会从暂停的地方重新开始,所以想更快,就不应该在首屏加载JS文件,全是建议在body标签底部写入script标签的

或者给script标签加上defer或者async属性,都会并行下载,同时不会阻塞渲染

上次更新: 2022/03/21, 11:27:08
浏览器的存储
浏览器的同源策略

← 浏览器的存储 浏览器的同源策略→

Copyright © 2021-2025 粤ICP备2021165371号
  • 跟随系统
  • 浅色模式
  • 深色模式