浏览器渲染机制和CRP优化

浏览器基础知识

通过浏览器访问页面,首先浏览器会请求回来一个HTML文档,然后自上而下开始渲染,这里面就包括进程和线程的基本概念

  • 进程: 指一个程序 ( 浏览器打开一个页面,就相当于开一个进行 )
  • 线程: 进程中具体执行事物的东西,一个线程同时只能做一件事
  • 同步编程: 一般是指一个线程去处理任务,上面的任务处理不完,下面的任务就无法处理
  • 异步编程:
    • 多线程异步编程
    • 单线程异步编程 ( Js是EventQueue + EventLoop 完成单线程异步编程的 )

浏览器中的主要线程

通过windows上的任务管理器可以看出,浏览器是可以开辟多进程和多线程的

浏览器的线程主要包括

  • GUI 渲染线程:渲染页面
  • JS 引擎线程:执行JS代码
  • HTTP 网络线程,可以开辟N个网络线程: 从服务器中获取资源和数据
  • 定时器监听线程
  • DOM监听线程
  • ….

页面渲染过程

  • 请求一个HTML文件,自上而下读取
  • CSS部分
    • 如果遇到style内嵌样式,GUI会直接渲染(同步)
      • 如果CSS代码较少,可以直接内嵌,拉取HTML的同时CSS也能获取到,直接参与渲染
      • 如果CSS代码较多,还通过内嵌分方式,一方面会影响HTML的获取速度,也不利于代码的维护 ;此时推荐外链的方式
    • 遇到 link 浏览器会开辟一个HTTP线程去请求资源文件,同时GUI线程会继续执行(异步)
      • 浏览器同时发送HTTP请求是有限制的;超过最大并发数其他的请求会暂时挂起
    • 遇到 @import ,浏览器也会开辟HTTP线程去拉去资源,但此时的GUI会暂停(导入样式会阻塞GUI的渲染),当资源请求回来, GUI才会继续
      • 真实项目中应该避免使用 @import
  • JS部分
    • 遇到<script src=””> 会阻碍GUI的渲染, 同时开辟HTTP线程去获取资源,请求结束运行JS引擎线程, 最后GUI才会渲染
      • 可以使用 window.addEventListener("load",callBack) ,等待页面所有资源都加载完,在执行
      • 可以使用 window.addEventListener("DOMContentLoaded",callBack) ,等待DOM树渲染完执行
      • <script src=”” aync/defer>
        • defer : 和 link 是类似的机制, 不会阻碍 GUI 的渲染,无论是HTTP线程还是JS线程,等GUI渲染完, 才会进行JS渲染线程
        • async : GUI渲染–单独开辟HTTP线程请求 ( 请求过程GUI不会停止,一旦请求结束会立即执行JS线程,同事终端GUI线程;等到JS线程完成后才会继续GUI线程 )
          • 问题: 如果 JS 引擎执行,GUI 没有完全渲染完成, 会存在部分 DOM 节点获取不到的情况
    • 注意: 如果多个 script请求 在没有任何属性方式下是顺序执行的; 如果属性是async,最先返回的先执行(并行);如果是 defer 浏览器内部会在 GUI 渲染完成后,等待所有设置 defer 的资源请求回来,在按照代码的顺序加载JS

总结

在真实项目开发中,我们一般把 link 放在页面的头部 【为了在没有 DOM 的时候,就通知HTTP去请求CSS,这样等DOM渲染完,CSS的资源也获取多了,更有效的安排时间,提高页面渲染效率】;把JS放在页面的底部,防止阻碍GUI的渲染,如果放在顶部,推荐设置 async、defer。


浏览器渲染过程

DOM树(渲染完成后触发 DOMCOntentLoaded 事件 -> [ 执行JS?如果有的话 ] -> CSSOM树 -> 渲染树(浏览器未来是按照这个树绘制的页面)-> Layout布局计算(重排)-> painting绘制(重绘)

关于重绘和重排

  • 页面第一次渲染必然会引发一次重排和重绘
  • 如果改变元素的大小和位置,浏览器也会进行重排;重排一定会触发重绘
  • 如果只是一些普通样式的更改例如color,只需要重绘即可

关于重排的优化方案(CRP优化)

  • 减少 DOM 的重排
  • 标签语义化和避免深层次嵌套
  • CSS 选择器是从右到左,比如:.box a{} 的性能要低于 a{} ;
    • 上述特点得出 less \ scss的预处理嵌套样式相对较差(阿里官方吐槽)
  • 对 JS 动态添加元素时采用代码片段的方式,一次性添加多个元素
  • 动画效果相对频繁的应用到 position 属性为 absolute或者fixed 的元素上(脱离文档流)
  • 使用 transform \ opacity \ filters 不会引发重排和重绘,但使用过多会占用大量内存,优势会导致字体模糊
  • 设置样式和获取样式分开(读写分离)
    • 在新版浏览器中存在 渲染队列机制,如果在设置元素过程中进行样式的读取会拆信一次渲染队列(会引发重排和重绘)
let box = document.querySelector("#box");
box.style.width = "100px" 
console.log(style.width) // 此时的的读取出会刷新渲染队列.浏览器进行一次重排
box.style.height = "100px" // 然后会进行第二次重排

上面一段代码,分别改变了 box 元的 width 和 height 属性,在渲染队列机制中对所有的更改机型队列执行,最后完成一次渲染,但在过程中如果出现读取元素,渲染队列会强制刷新,以确保获取的元素属性是目前最新的状态,这样以来针对 height 的更改触发队列中的第二次渲染。所以优化方法就是尽可能将操作和读取元素区分来写,即读写分离。

let box = document.querySelector("#box");
box.style.width = "100px" 
box.style.height = "100px"
console.log(style.width)

读写分离的好处在于,不打断渲染队列的情况,让浏览器针对于本次队列的内容统一渲染一次到页面,从而避免了重复触发重排,提高页面渲染性能

本片文章借鉴《珠峰前端高级体系课程》,如有侵权行为,请联系作者删除​

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇