浏览器底层渲染机制

本文探讨了浏览器的渲染机制,包括进程和线程、关键渲染路径以及样式、图片和脚本的处理方式。强调了同步和异步编程的概念,并提供了针对样式、图片和JavaScript的性能优化策略,如懒加载、合并资源和使用async或defer属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

进程和线程

浏览器具备的线程:

当我们从服务器获取HTML之后,浏览器需要按照代码规则,绘制出对应的页面

加快页面第一次渲染,减少白屏等待时间

遇到

遇到(外链式):

遇到@import(导入式):

遇到:

遇到


前言:

两个概念:

进程和线程

进程:一个程序,浏览器打开一个页面就开辟一个进程
线程:程序中具体"干活"的人,浏览器具备很多线程,这样就可以同时做很多事情
一个进程中包含一到多个线程,

  • 每一个线程同时只能做一件事,这件事情处理完成,才能处理下一件事情 =>这个操作叫"同步编程"
    同步编程的特点:单线程,同时只能处理一件事情,上件事情处理完,才能处理下一件事情!(只有一个线程,这件事情没有干完,下件事不能干)
  • "异步编程":多线程,同时可以处理多件事情

进程就好比是一个奶茶店,线程就是服务员~(便于理解哦)

浏览器具备的线程:

  • GUI渲染线程:自上而下渲染页面的「含:HTML、CSS、IMG...」
  • JS引擎线程:渲染和解析JS代码
  • HTTP网络请求线程:从服务器端获取内容「最多同时可以开辟5~7个」(http并发数)
  • 定时器监听线程:监听定时器是否到达时间
  • 事件监听线程:监听事件是否触发

这种前端性能优化方案,有个专业名词叫做"CRP",CRP叫关键渲染路径,它是一种优化思想:了解浏览器的每一步处理机制,针对每一步去做优化

当我们从服务器获取HTML之后,浏览器需要按照代码规则,绘制出对应的页面

@1 创建"DOM TREE"
GUI渲染线程会自上而下,一行行的渲染解析页面中的代码;当渲染到底部的时候,浏览器已经规划出:当前页面的结构和层级嵌套关系(节点和节点之间的关系) -> 这就是DOM树
@2 创建"CSSOM TREE"

在DOM TREE生成后,浏览器把(从服务器获取的)样式代码进行渲染,生成CSSOM树!
在GUI渲染过程中,我们会遇到<link>、<style>、@import 、<img>、<script>...等标签,遇到不同的标签有不同的处理方案!

@3 把"DOM TREE"和"CSSOM TREE"合并在一起,生成"RENDER TREE"

前三步都是为了规划和计算每个节点有什么样式

@4 Layout布局:根据视口大小,计算出每一个节点在视口中的具体位置及大小等

@5 分层:规划出对应的层级,以及节点该在哪一个层级上「脱离文档流」

@6 Painting绘制:按照所有解析出来的规则,一层层的开始绘制


加快页面第一次渲染,减少白屏等待时间

关于样式:

遇到<style>(内嵌式):

无需去服务器获取样式代码了,但是也不会立即渲染,也是要等到DOM TREE生成完,外链式获取的样式也都拿到了,然后按照编写的先后顺序,依次渲染解析样式代码,以此保证CSS优先级正确!

遇到<link>(外链式):

单独开辟一个新的HTTP线程去服务器获取样式代码,而GUI渲染线程会继续向下渲染「异步操作」;也就是CSS样式代码的渲染,一般都发生在DOM TREE 生成之后!

遇到@import(导入式):

也会开辟一个HTTP线程从服务器获取样式代码,只不过它会阻碍GUI渲染;也就是,样式代码没有请求回来之前,GUI暂停渲染!「同步编程」

优化方案:

@1 样式代码较少的情况下,我们直接基于内嵌式<style>放在HTML页面中即可,没必要从服务器获取,这样可以在DOM TREE生成后,立即渲染样式,生成DOM TREE,加快页面渲染的速度!「移动端经典优化方案

@2 样式代码较多,我们基于外链式<link>;

  • 我们最好把CSS都写入到一个样式表中,只请求一次即可减少HTTP请求次数

例如:100kb,一次10kb,分10次请求回来好,还是一次请求100kb好,

一次好,因为多次也是等待全部回来之后,再渲染,浏览器最多开辟wu~七个线程;如果http请求发多了,网络通道堵塞

  • 把<link>放在HEAD中,这样保证样式资源的提前获取,当DOM TREE生成后,可能样式代码已经回来了!

@3 非必要情况,不用@import,因为它会阻碍GUI的渲染

遇到<img>:

  • 首先开辟一个新的HTTP线程去请求图片,GUI继续向下渲染「异步编程」
  • 当获取到图片资源后,浏览器首先进行编码,然后按照编码进行渲染绘制!

正常情况下,它遇到img src图片渲染,分成三步,获取、编码、绘制,想要渲染的速度更快一点儿,直接跳过获取和编码过程。

优化方案:

@1 虽然请求图片资源不会阻碍GUI渲染,但是每一次请求,都占用了一个HTTP线程,而浏览器可同时开辟的HTTP是有数量限制的,所以最开始加载真实图片,可能会导致其他类型资源获取延后...所以我们需要做图片的"懒加载"

@2 "BASE64":如果想加快图片的渲染,我们可以跳过 获取资源&编码 这两步,直接让浏览器绘制即可

压缩工具网站:

JS压缩, CSS压缩, javascript compress, js在线压缩,javascript在线压缩,css在线压缩,YUI Compressor压缩,Google Closure Compiler压缩,js压缩,uglifyjs压缩,javascript压缩,js美化,javascript美化,js加密,js解密,js混淆,javascript加密,javascript解密,js格式化,javascript格式化

  • 如果图片较大,生成的BASE64码会超级多,这样增加了CSS文件的体积,而且代码维护起来会很麻烦,所以不要滥用BASE64;
  • 小图片可以BASE64;大图只有在各种解决办法都试过之后,发现还是达不到自己要求,此时尝试用BASE64,发现图片渲染速度会明显提高!{我们后期基于webpack可以自动打包时候BASE64}(写代码的时候,不写BASE64,最后,经过webpack打包部署到服务器上,自己变成BASE64)

遇到<script src='xxx.js'>:

  • 开辟新的HTTP线程去获取JS代码,同时阻碍了GUI的渲染「同步编程」

优化方案:

@1 把<script>放在页面底部

@2 <script>获取资源改为异步编程「不让其阻碍GUI渲染」

  • <script async>:GUI渲染中,遇到<script async>,开辟HTTP线程去获取JS代码;获取的过程中,GUI继续向下渲染,但是获取到了之后,立即暂停GUI,先把获取的JS先执行,执行完GUI继续!
  • <script defer>:和<link>很相似,遇到<script defer>,开辟HTTP线程,异步去获取JS代码,GUI继续渲染;哪怕当JS代码拿回来后,也要等GUI渲染完,而且所有设置defer的JS都获取完,按照编写的先后顺序,依次渲染解析JS!
  • <script>:GUI渲染中,遇到script,则暂停渲染,然后获取JS代码,获取后把JS渲染解析;都完成后,GUI继续渲染!
// window.onload : 页面中所有资源都加载完成「含DOM TREE」
window.onload = function () {
    console.log(document.querySelector('.box'));
};
// DOMContentLoaded :只要DOM TREE生成就可以触发
window.addEventListener('DOMContentLoaded', function () {
    console.log(document.querySelector('.box'));
});

 

什么时候用async和defer?

如果没有JS之间的相互依赖,完全可以先回来执行谁,使用async即可;但凡需要根据导入的先后循序去执行才可以,则一定要用defer;

@3 和CSS一样,最好所有的JS都合并到一个文件中,减少HTTP请求次数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值