前端资源浏览器渲染原理

news2024/12/23 6:14:10

浏览器的渲染页面过程

HTML解析过程

一般情况下服务器会给浏览器返回 xx.html 文件 解析html 其实就是 Dom 树的构建过程

我们可以根据以下html 结构 来简单的分析出 html 的解析过程

image-20230224173537427

image-20230224173452450

解析CSS 规则树

在解析的过程中,如果遇到CSS的link元素,那么会由浏览器负责下载对应的CSS文件:

PS: 这里下载 CSS 是不会影响到 DOM树的解析的

下载完成后 就会对CSS 文件解析出对应的 规则树 , 案例如下图 :

body{font-size: 16px}
p{font-weight: bold}
span{color: red}
p span{display:none}
img{float: right}

image-20230224173851072

解析步骤 构建 Render Tree

当有了DOM Tree和 CSSOM Tree后,就可以两个结合来构建Render Tree了

image-20230224173938905

需要注意的是:

  • link元素不会阻塞DOM Tree的构建过程,但是会阻塞Render Tree的构建过程
  • Render Tree和DOM Tree并不是一一对应的关系,比如对于display为none的元素,压根不会出现在render tree中;

解析步骤 布局和绘制

  • 渲染树(Render Tree)上运行布局(Layout)以计算每个节点的几何体。
    • 渲染树会表示显示哪些节点以及其他样式,但是不表示每个节点的尺寸、位置等信息;
    • 布局是确定呈现树中所有节点的宽度、高度和位置信息;
  • 将每个节点绘制(Paint)到屏幕上
    • 在绘制阶段,浏览器将布局阶段计算的每个frame转为屏幕上实际的像素点;
    • 包括将元素的可见部分进行绘制,比如文本、颜色、边框、阴影、替换元素(比如img)

渲染的流程可以参考下图 :

image-20230224174204939

完成以上五步 成功在浏览器渲染出 对应的 xx.html 文件

回流和重绘

回流(reflow)

reflow

  • 我们渲染出来的节点大小位置 也就是布局时第一次渲染出之后就确定的
  • 之后对于节点大小和位置重新计算的行为 叫做回流(reflow)

回流在什么时候会出现 :

  1. DOM 结构发生变化 (添加 & 移除)
  2. 改变了 CSS 样式代码 也就是布局
  3. 修改了 窗口尺寸
  4. 或者是调用了某些内置函数 获取位置和尺寸信息

重绘 (reprint)

  • 我们渲染的第一次,在之前的流程图中叫做 printing
  • 在之后需要重新渲染的时候 成为重绘

重绘怎么出现 :

  1. 修改CSS 如 颜色 文字样式

拓展思路

  1. 只要出现回流 就一定会引起重绘 其实看到上述的解释 也很容易就发现 回流也是在出发样式代码或者改变的时候触发
  2. 回流的性能并不好 也很明显 重新渲染整个DOM 很浪费性能

总结

  • 修改样式 尽可能减少回流次数 也就是设计好之后,非必要不去改动样式和DOM的结构
  • 避免频繁使用 JS 去操作DOM
  • 尽可能减少函数获取储存位置的信息

特殊解析 - composite合成

绘制的过程,可以将布局后的元素绘制到多个合成图层中。

会形成新的合成层的属性:

  • 3D transforms
  • video、canvas、iframe
  • opacity 动画转换时
  • position: fixed
  • will-change
  • animation 或 transition 设置了opacity、transform

PS:分层确实可以提高性能,但是它以内存管理为代价,所以不作为性能优化策略来使用

script元素和页面解析的关系

JS 在我们渲染过程中的那一步呢?

  1. 在渲染html的时候 js 没有继续构造DOM的能力
  2. 如果需要需要的部分 会先停止构建,下载js 执行脚本
  3. 把需要构建的东西构建完成后 继续执行构建 DOM

这么做有什么好处?

  1. JS 有操作和修改DOM的作用
  2. 为什么会先去执行js脚本? 因为之前提到了 回流时很吃性能的所以最好一次性弄好 减少不必要的回流

代码案例

index.html

<script src="./js/test.js"></script>

<body>
    <div class="box"></div>
</body>
<script>
    var boxel = document.getElementsByClassName("box")
    console.log(boxel);
</script>

test.js

debugger
console.log("hello")

新的问题:

  • 在现在的开发模式中 大多都是使用vue和React 作为开发框架 JS 的占比往往很大 处理事件也会变长
  • 这也导致了 如果解析阻塞 那么在脚本解析完成之前 可能界面什么都不显示

这里 js 给我们提供了两个属性 来解决这个问题

defer属性

defer 属性告诉浏览器不要等待脚本下载,而继续解析HTML,构建DOM Tree,如果脚本提前下载好就等待加载,等DOM完成 在触发DOMContentLoaded之前执行defer中的代码

PS: defer 按照默认顺序执行 不会影响顺序 且可以操作DOM

<script>
    window.addEventListener("DOMContentLoaded", () => {
        console.log("DOMContentLoaded");
    })
</script>
<script>
    var boxel = document.getElementsByClassName("box")
    console.log(boxel);
</script>
<script defer>
    console.log("defer-demo")
</script>
<script>
    debugger
    console.log("hello")
</script>

建议:

  • 将defer放入head中使用 这个属性的特性放在末尾 就本末倒置了
  • defer 只对外置脚本有效果

async属性

async 特性与 defer 有些类似,它也能够让脚本不阻塞页面。

它的特性:

  • 浏览器不会因 async 脚本而阻塞(与 defer 类似);
  • async脚本不能保证顺序,它是独立下载、独立运行,不会等待其他脚本
  • async不会能保证在DOMContentLoaded之前或者之后执行
<script>
    window.addEventListener("DOMContentLoaded", () => {
        console.log("DOMContentLoaded");
    })
</script>
<script async>
    console.log("defer-demo")
</script>

总结

  • defer 通常用于文档解析操作DOM且有顺序要求的JS代码
  • async 通常用于独立脚本 可以理解为没有什么依赖的脚本 如果有依赖 那么不保证一定能提前加载到

总结

  1. 首先时了解和认识一些浏览器的内核
  2. 了解从服务器加载 到渲染页面的流程
  3. 细化每一步的大致内容
  4. 发现有问题且探索到问题的一些解决方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/372228.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享 7 个有用的 JavaScript 库,也许你会用的上

使用这7个库&#xff0c;加速你的项目开发当我们可以通过使用库轻松实现相同的结果时&#xff0c;为什么还要编写自定义功能&#xff1f;开发人员最好的朋友和救星就是这些第三方库。我相信一个好的项目会利用一些可用的最佳库。本系列就是帮助前端开发者整理一些相关的优秀的J…

一文了解互联网中的UI设计师

&#xff08;点击即可收听&#xff09;一文了解UI设计师UI设计师是什么岗位,以及它的职责所在是什么,初入职场,今天带你一起来了解一下宏观上:设计师微观上: 上游对接产品经理,根据产品经理产出的PRD(也就是产品文档手册),以及产品原型,设计产品的UI界面,产出设计稿(如:蓝湖,Sk…

vite:常见的配置

最近在捣鼓一下vite&#xff0c;因为自己一直在使用react&#xff0c;就选择vite、react来体验一下vite。 使用最简单的方法创建一个应用&#xff1a;yarn create vite&#xff0c;然后选择react框架。 vite默认配置是使用了defineConfig工具函数&#xff1a; import { defi…

TCP协议原理二

文章目录四、滑动窗口二、流量窗口三、拥塞控制四、滑动窗口 前面我们学习了 确认应答&#xff0c;超时重传&#xff0c;连接管理&#xff0c;这些机制都为我们TCP的可靠性提供了保证&#xff0c;当然在保证TCP的可靠性的同时&#xff0c;传输效率也受到了一定的影响&#xff…

[创业之路-56] :职场真相:越便宜的员工其实越贵

引言&#xff1a;创业公司由于资金的限制&#xff0c;喜欢招聘经验不多、价格便宜的员工&#xff0c;殊不知&#xff0c;放在宏观的视角看&#xff0c;越发发现&#xff0c;越便宜的员工其实越贵&#xff0c;虽然他们能加班、好学习、听话&#xff0c;但创业公司不是大学&#…

【华为OD机试模拟题】用 C++ 实现 - 剩余可用字符集 or @分割可用字符集(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 获得完美走位(2023.Q1) 文章目录 最近更新的博客使用说明剩余可用字符集 or @分割可用字符集题目输入输出示例一输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才…

LLVM高级架构介绍

LLVM 为什么要开一个LLVM的新坑呢&#xff1f; 我从智能穿戴转行到芯片软件行业&#xff0c;从事编译器开发&#xff0c;不过是AI编译器。不过基本的传统编译器还是绕不过去啊&#xff0c;所以开始学习LLVM&#xff0c;后面开始学习TVM&#xff0c;MLIR。 LLVM GitHub地址 L…

vue-知识点总结

历史 2015年 10月27 1.0.0 Evangelion 新福音战士2016年 10月1日 2.0.0 Ghost in the Shell 攻壳机动队2019年 2月 2.62020年 9月18日 3.0.0 One Piece(海贼王)2021年 8月10日 3.2.0 .sync where 父向子传递props, 需要双向绑定的时候(子组件想更新这个值) how <one-comp…

vscode配置drawio绘制流程图

目录 vscode配置drwaio drawio使用 添加元素 调整元素 连接元素 添加公式 图像与表格 组合元素 保存以及导出 最近课程设计需要画流程框图&#xff0c;所以在网上找找绘制流程图的软件。然后我选择了这个drawio&#xff0c;无他&#xff0c;只是因为用vscode插件就…

同步和异步promise

进程和线程进程&#xff08;厂房&#xff09;&#xff1a;程序的运行环境线程&#xff08;工人&#xff09;&#xff1a;进行运算的东西同步和异步同步&#xff1a;一件事干完才去干下一件事&#xff0c;前面的代码不执行&#xff0c;后面的代码也不执行。同步的代码可能会出现…

lesson01_ts知识回顾

基本数据类型 undefined 和 null 可赋值给其他基本数据类型 let num: number 3; let flag: boolean false; let str: string "abc";let a: null null; let b: undefined undefined;联合数据类型 let variable: number | boolean false; variable 123;数组 …

指针的进阶【中篇】

文章目录&#x1f4c0;4.数组参数&#x1f4bf;4.1.一维数组传参&#x1f4bf;4.2.二维数组传参&#x1f4c0;5.指针参数&#x1f4bf;5.1.一级指针传参&#x1f4bf;5.2.二级指针传参&#x1f4c0;6.函数指针&#x1f4bf;6.1. 代码1&#x1f4bf;6.2. 代码2&#x1f4c0;7.函…

Linux 进程:理解进程和pcb

目录一、进程的概念二、CPU分时机制三、并发与并行1.并发2.并行四、pcb的概念一、进程的概念 什么是进程&#xff1f; 进程就是进行中的程序&#xff0c;即运行中的应用程序。比如&#xff1a;电脑上打开的LOL、QQ…… 这些都是一个个的进程。 什么是应用程序&#xff1f; 应用…

【java基础】static和final关键字的作用及其用法详解

文章目录static关键字静态字段静态方法静态代码块静态内部类final关键字final字段final方法final类static关键字 这个关键字表示静态的&#xff0c;用于不同地方意思不一样 静态字段 如果我们将其作用到字段上&#xff0c;那么该字段为类所拥有&#xff0c;我们使用new关键字…

【Node.js】 Express编写接口和跨域解决的方法!

Node.jsExpress编写接口接口跨域问题使用cors中间件解决跨域问题CORS响应头分类&#xff1a;CORS请求分类&#xff1a;编写JSONP接口Express编写接口 注意想获取URl-encoded格式的请求体数据&#xff0c;必须配置中间件app.use(express.urlencoded({extended:false}))创建api路…

动态规划:leetcode 1049.最后一块石头的重量II、494.目标和、474.一和零

leetcode 1049.最后一块石头的重量IIleetcode 494.目标和leetcode 474.一和零leetcode 1049.最后一块石头的重量II有一堆石头&#xff0c;每块石头的重量都是正整数。每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&am…

【算法经典题集】递归(持续更新~~~)

&#x1f63d;PREFACE&#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐ 评论&#x1f4dd;&#x1f4e2;系列专栏&#xff1a;算法经典题集&#x1f50a;本专栏涉及到的知识点或者题目是算法专栏的补充与应用&#x1f4aa;种一棵树最好是十年前其次是现在1.递归1.1 递归实现…

【JAVA】常见的七大排序

前言&#xff1a;本篇主要介绍常见的七大排序&#xff0c;实现语言为Java&#xff0c;其主要分为&#xff1a;直接插入排序&#xff0c;希尔排序&#xff0c;直接选择排序&#xff0c;堆排序&#xff0c;冒泡排序&#xff0c;快速排序&#xff0c;归并排序。 在介绍七大排序之前…

【多尺度密集递归融合网络:超分】

A novel image super-resolution algorithm based on multi-scale dense recursive fusion network &#xff08;基于多尺度密集递归融合网络的图像超分辨率算法&#xff09; 随着卷积神经网络(CNN)技术的成熟度,超限分辨的图像重建(SR)方法基于CNN正在蓬勃发展,取得了许多显…

RIP路由协议的更新(电子科技大学TCP/IP第二次实验)

一&#xff0e;实验目的 1、掌握 RIP 协议在路由更新时的发送信息和发送方式 2、掌握 RIP 协议的路由更新算法 二&#xff0e;预备知识 1、静态路由选择和动态路由选择 2、内部网关协议和外部网关协议 3、距离向量路由选择 三&#xff0e;实验原理 RIP 协议&#xff08…