性能优化之-更高效的数据渲染

news2024/11/17 9:46:56

前言:中心思想还是让请求的资源得到更快响应的方法,比如压缩资源,减少数据量的大小,缓存数据以减少请求数量,http/2让网络传输变得更快这些,下面就让我们来看看浏览器是如何解析这些数据,最终又是如何将他们渲染在屏幕上的?在数据量不变的情况下还有哪些可以优化的点?

浏览器怎么渲染的,从输入一个路径地址开始

当浏览器获得一个html文件时,会“自上而下”加载,并在加载过程中进行解析渲染。
步骤: 构建DOM 和 CSSOM -> 构建render树 -> 布局render树 -> 绘制render树

1. 将HTML解析成一个DOM(文档对象模型)

浏览器会解析html文件中的标签,例如:<html></body><p>,给这些标签打上标记,遇到标记后浏览器使用令牌生成器开始生成令牌,例如:<p>hello</p>这样一个文本标签会生成:StartTag:p, hello, EndTag:p这样3个令牌,接着生成对应的nodes(节点)后就形成了DOM,也就是文档对象模型(Document Object Model,简称DOM))
![在这里插入图片描述](https://img-blog.csdnimg.cn/fe932a8694dd40bc927fec0f0a07cd34.png
在这里插入图片描述
在这里插入图片描述

2. 将CSS解析成 CSSOM(层叠样式表对象模型)

当html解析中遇到< link >标签时,会请求对应的CSS文件,当CSS文件就位时便开始解析它(如果遇到行内< style

时则直接解析),这一解析过程可以和构建DOM同时进行。 那其实css树构建的过程和dom树类似。也是经历了打标记, 生成令牌和节点的过程,不过这里的识别标记规则和dom不一样,因为css拥有继承属性的操作方式,父级部分属性样式会被子级样式继承,比如字体font-size,
font-weight, font-style,
行高line-height等,还有部分默认样式,如下图箭头所指便是默认的样式,红色框内是继承样式。

在这里插入图片描述

3. 构造 Rendering Tree。

根据DOM树,会遍历每一个可见的节点,对于每一个可见的节点,在CSSOM上找到匹配的样式并应用,生成Rendering Tree。
此时渲染树并不等同于构建DOM 树,因为如果遇到不可见(display:none)属性,会跳过该元素和其子项。另外在html的head里不包含任何可见信息,所以这部分的内容会被很快的去除;
在这里插入图片描述

4. 布局

有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步就是计算出每个节点在屏幕中的位置和大小,这个操作称之为Layout。

5. 绘制

即遍历render树,并使用UI后端层绘制每个节点以像素显示在屏幕上。
这里需要注意的是:
1、 并不是所有的数据都已经加载出来了,而是先显示一部分,再显示另一部分。
2、 虽然是从上往下加载,但并不是一定要等着上面的内容显示之后才显示下面的内容,而是谁解析的快,就渲染的越快。
3、 CSS 加载不会阻塞 DOM 的加载,但是会阻塞 Dom 的渲染。虽然DOM 和 CSSOM 通常是并行构建的,但是Render Tree 是依赖于 DOM Tree 和 CSSOM Tree 的,所以他必须等待到 CSSOM Tree 构建完成,也就是 CSS 资源加载完成后,才能开始渲染。
如果引用的是外部样式,需要等待这些样式全部加载完后,才开始构建CSSOM。因为css文件中包含大量的样式,后面的样式会覆盖前面的样式,如果我们提前就构建CSSDOM,可能会得到错误的结果。
4、 JS文件不只是阻塞DOM的构建,它会导致CSSOM也阻塞DOM的构建;在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建。
这是因为JavaScript不只是可以改DOM,它还可以更改样式,也就是它可以更改CSSOM。因为不完整的CSSOM是无法使用的,如果JavaScript想访问CSSOM并更改它,那么在执行JavaScript时,必须要能拿到完整的CSSOM。也就是说,在这种情况下,浏览器会先下载和构建CSSOM,然后再执行JavaScript,最后在继续构建DOM。
所以,如果我们想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因。当然在当下,并不是说 script 标签必须放在底部,因为你可以给 script 标签添加 defer(延迟执行) 或者 async(异步下载) 属性;

关键渲染路径优化

关键渲染路径是浏览器将 HTML、CSS、JavaScript
转换为在屏幕上呈现的像素内容所经历的一系列步骤。也就是我们刚刚提到的的的浏览器渲染流程。

1、将能快速解析的数据放在前面,不好解析的放在后面

html语义化标签加强DOM解析,因为语义化标签是浏览器内置就能解析识别的标签;
尽量不要使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局,并且table不是一点一点加载渲染的,是一整个加载好了才渲染的;
一些装饰性元素可以适当的使用伪元素,避免增加无意义的页面元素;

2、让CSSOM不阻塞DOM的渲染

并不是所有的CSS资源都那么的 『关键』

举个例子:一些响应式CSS只在屏幕宽度符合条件时才会生效,还有一些CSS只在打印页面时才生效。这些CSS在不符合条件时,是不会生效的,所以我们为什么要让浏览器等待我们并不需要的CSS资源呢?
我们可以将打印相关的CSS移动到print.css,然后我们在HTML中引入CSS时,添加媒体查询属性print,代码如下:

上面代码添加了media="print"属性,所以上面CSS资源仅用于打印。添加了媒体查询属性后,浏览器依然会下载该资源,但如果条件不符合,那么它就不再阻塞渲染;

上面提供的方法是针对那些不需要生效的CSS资源,如果CSS资源需要在当前页面生效,只是不需要在首屏渲染时生效,那么为了更快的首屏渲染速度,我们可以将这些CSS也设置成非关键资源。只是我们需要一些比较hack的方式来实现这个需求:

<link href="style.css" rel="stylesheet" media="print" onload="this.media='all'">

上面代码先把媒体查询属性设置成print,将这个资源设置成非阻塞的资源。然后等这个资源加载完毕后再将媒体查询属性设置成all让它立即对当前页面生效。

类似的方案还有,代码如下:

<link rel="preload" href="style.css" as="style" onload="this.rel='stylesheet'">
<link rel="alternate stylesheet" href="style.css" onload="this.rel='stylesheet'">

总结一下就是把首屏渲染需要使用的CSS通过style标签内嵌到head标签中,其余CSS资源使用异步的方式非阻塞加载。优化过后可以对照看一下FP(首次绘制)的时间点有没有提前。
image.png

3、尽可能的不使用 @import 属性,import属性会在页面加载完成之后,等效于把css写到文档的底部,并且加载多个css文件时是串行加载,所以应该避免这种情况。

4、CSS 选择符从右往左匹配查找,应避免节点层级过多,并适当使用子选择器,例如 .list>a>img

5、异步JavaScript

为了避免阻塞,可以为script标签添加async或者defer属性。async的执行是加载完成就会立马去执行,而不像defer那样要等待所有的脚本加载完后按照顺序执行,下面可以听过这个两张图来对比一下他们的区别:

蓝色:文档解析
紫色:脚本加载
黄色:脚本执行
绿色: HTML 文档被完全加载和解析完成

defer

适用于如果你的脚本代码依赖于页面中的DOM元素(文档是否解析完毕),或者被其他脚本文件依赖时。
image.png

async

适用于如果你的脚本并不关心页面中的DOM元素(文档是否解析完毕),并且也不会产生其他脚本需要的数据时。
image.png

6、减少JS操作 DOM 的次数

把 DOM 和 JavaScript 各自想象成一个岛屿,它们之间用收费桥梁连接。——《高性能 JavaScript》

DOM 是属于渲染引擎中的东西,而 JS 又是 JS 引擎中的东西。当我们用 JS 去操作 DOM 时,本质上是 JS 引擎和渲染引擎之间进行了“跨界交流”。这个“跨界交流”的实现并不简单,它依赖了桥接接口作为“桥梁”。
image.png

过“桥”要收费——这个开销本身就是不可忽略的。我们每操作一次 DOM(不管是为了修改还是仅仅为了访问其值),都要过一次“桥”。过“桥”的次数一多,就会产生比较明显的性能问题。因此“减少 DOM 操作”的建议,并非空穴来风。

1、最常见的缓存Dom对象
操作Dom一般首先会去访问Dom,尤其是像循环遍历这种事件复杂度可能会比较高的操作,那么可以在循环之前就将主节点,不必循环的Dom节点先获取到,那么在循环里就可以直接引用,而不必去重新查询。

image.png

2、vue虚拟节点
虚拟Dom是js模似DOM树并对DOM树操作的一种技术。virtual DOM是一个纯js对象(字符串对象),所以对他操作会高效。
在dom发生变化的时候对虚拟dom进行操作,通过dom diff算法将虚拟dom和原虚拟dom的结构做对比,最终批量的去修该真实的dom结构,尽可能的避免了频繁修改dom而导致的频繁的重排和重绘。

减少 reflow/repaint

Reflow(重排):当浏览器发现某个部分发生了变化,影响了布局,我们需要重新验证并计算Render Tree。是Render Tree的一部分或全部发生了变化——这就是Reflow,或是Layout。

Repaint(重绘):如果只是改变了某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引起浏览器的重绘,重画某一部分。

因此看出,重排要比重绘更花费时间,也就更影响性能。所以在写代码的时候,要尽量避免过多的重排。

以下操作会导致重排或重绘:

  • 删除,增加,或者修改DOM元素节点。

  • 改变元素的大小,位置时,或者将使用display:none时,会造成重排;修改CSS颜色或者visibility:hidden等等,会造成重绘。

  • 修改网页的默认字体时。 Resize窗口的时候(移动端没有这个问题),或是滚动的时候。 内容的改变,(用户在输入框中写入内容也会)。

  • 激活伪类,如:hover。

1、减少DOM操作,比如改变元素的尺寸,位置,显隐等。可以预先定义好 css 的 class,然后修改 DOM 的 className;

2、为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会 reflow 的。

3、隐藏元素,进行修改后,然后再显示该元素。

4、可以使用文档片段创建一个子树,然后再拷贝到文档中,文档片段是一个轻量级的document对象,它设计的目的就是用于更新,移动节点之类的任务,而且文档片段还有一个好处就是,当向一个节点添加文档片段时,添加的是文档片段的子节点群,自身不会被添加进去。

let fragment = document.createDocumentFragment();
appendNode(fragment, data);
ul.appendChild(fragment);

懒加载(延迟加载)

1、图片懒加载

对页面加载速度影响最大的就是图片,一张普通的图片可以达到几M的大小,而代码也许就只有几十KB。当页面图片很多时,页面的加载速度缓慢,几S钟内页面没有加载完成,用户会失去耐心。
为了加速页面加载速度,所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。参考库:vue-lazyload

<img v-lazy="/static/img/1.png">

2、路由懒加载

把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样做可以减少无效资源的加载,明显减少服务器的压力和流量,也能够减小浏览器的负担。
实现:结合 Vue 的异步组件和 Webpack 的代码分割功能

const Foo = () => import('./Foo.vue')
router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ]})

(图片 素材都来源网络,侵权联系立马删)

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

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

相关文章

数据结构——红黑树

红黑树 概念与性质树节点的定义插入红黑树的验证红黑树与AVL树的对比 概念与性质 概念&#xff1a; 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色…

数字IC设计——功耗分析

一、概述 芯片的整体功耗很难通过简单的电流&#xff0c;电压或者电阻值的的相乘来计算。其原因在于&#xff0c;由于芯片作为具有复杂功能的器件&#xff0c;其功耗会根据其不同时段的不同行为&#xff0c;不同的外部条件而发生很大的变化。 1.1 功耗的分类 数字IC芯片的功…

Three.js+TypeScript+Webpack学习记录(二)

使用环境参考 Node.js v16.19.1 正文 跟着文档画个线 看看 Three 的官方文档&#xff0c;起步 -> 画线 -> 没了&#xff1f;&#xff01;&#xff01; 不管怎么说&#xff0c;先画个线吧。 import * as THREE from threeconst scene new THREE.Scene() const camer…

HummerRisk V1.0 开发手册(微服务版)

HummerRisk 是开源的云原生安全平台&#xff0c;以非侵入的方式解决云原生环境的安全和治理问题。核心能力包括混合云的安全治理和容器云安全检测。 本文将介绍HummerRisk 1.0以后的开发准备工作。 v1.0.0 以后的版本&#xff0c;代码在 dev 分支。欢迎大家在 dev 开发分支提…

多通道振弦传感器无线采集仪 数字传感器起始通道分配

多通道振弦传感器无线采集仪 数字传感器起始通道分配 寄存器 DS_CHNUM(299)用于设置读取到的数字传感器数据从哪个通道开始占用&#xff0c;默认为 1。 单个数字传感器占用的通道数量与具体的传感器类型有关&#xff0c;例如&#xff1a;每个激光测距仪会占用 1 个通道&#xf…

Linux Shell 实现一键部署二进制go+caddy+filebrowser

filebrowser filebrowser 是一个使用go语言编写的软件&#xff0c;功能是可以通过浏览器对服务器上的文件进行管理。可以是修改文件&#xff0c;或者是添加删除文件&#xff0c;甚至可以分享文件&#xff0c;是一个很棒的文件管理器&#xff0c;你甚至可以当成一个网盘来使用。…

HCIE Datacom认证学什么内容

什么HCIE 什么是HCIE&#xff1f;HCIE的全称是Huawei Certified ICT Expert&#xff08;华为认证ICT技术专家&#xff09;。 华为认证是行业中最严谨的认证&#xff0c;含金量与行业认可度都较高。在众多的IT行业认证中&#xff0c;HCIE被誉为“网络界的博士”。 华为认证HCI…

深度学习 - 41.Word2vec、EGES 负采样实现 By Keras

目录 一.引言 二.实现思路 1.样本构建 2.Word2vec 架构 3.EGES 架构 4.基于 NEG 的 Word2vec 架构 三.Keras 实现 Word2vec 1.样本构建 2.模型构建 3.向量获取 四.keras 实现 EGES 1.样本构建 2.模型构建 3.Dot Layer 详解 3.1 init 方法 3.2 call 方法 3.3 完…

4月18号软件更新资讯合集

ModStartCMS v6.2.0&#xff0c;VIP 权益配置功能、界面 UI 优化升级 ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;基于 Apache 2.…

4月19号软件更新资讯合集....

JavaWeb 微服务前后端分离 EurekaEleVue 版 v1.5.0 发布 v1.5.0 更新如下&#xff1a; 1、解决 token 过期无法跳转至登录页的问题&#xff1b; 2、授权服务进行重构与优化&#xff1b; 一款 Java 语言基于 SpringCloud、SpringSecurity、OAuth2、Eureka、Vue、ElementUI、…

Docker实战笔记1-基础

转载请标明出处&#xff1a;http://blog.csdn.net/zhaoyanjun6/article/details/130181636 本文出自【赵彦军的博客】 文章目录 官网下载安装安装Docker 镜像镜像分层存储 容器常用命令docker infodocker imagesdocker versiondocker ps &#xff1a;查看容器docker ps -a查看容…

如何检查设置的IP是否有效?Storm proxies动态代理IP好用吗?

检查设置的IP是否有效可以通过以下几种方式&#xff1a; 发起网络请求&#xff1a;可以使用HTTP客户端库&#xff08;例如Python的Requests库&#xff09;或者命令行工具&#xff08;例如curl&#xff09;来发起网络请求&#xff0c;使用设置的IP作为代理IP&#xff0c;然后查看…

读SQL进阶教程笔记12_地址与三值逻辑

1. SQL和数据库都在极力提升数据在表现层的抽象度&#xff0c;以及对用户隐藏物理层的概念 2. 关系模型是为摆脱地址而生的 2.1. “地址”不仅包括指针操作的地址&#xff0c;还包括数组下标等 3. 一个优雅的数据结构胜过一百行杂耍般的代码 3.1. 精巧的数据结构搭配笨拙的…

数据结构入门——顺序表(保姆级教程,增,删,改,查)

1.什么是顺序表 1.顺序表&#xff1a;可动态增长的数组&#xff0c;要求数据是连续存储的 2.顺序表的定义&#xff1a; 静态顺序表&#xff1a;使用定长数组存储元素&#xff08;缺点&#xff1a;小了不够用&#xff0c;大了还浪费&#xff09; 动态顺序表&#xff1a;可根…

744. 寻找比目标字母大的最小字母

给你一个字符数组 letters&#xff0c;该数组按非递减顺序排序&#xff0c;以及一个字符 target。letters 里至少有两个不同的字符。 返回 letters 中大于 target 的最小的字符。如果不存在这样的字符&#xff0c;则返回 letters 的第一个字符。 示例 1&#xff1a; 输入: le…

3. VBA术语

在本章中&#xff0c;将介绍常用的Excel VBA术语。这些术语将在很多的模块中使用&#xff0c;因此理解其中的每一个术语都很重要。 3.1 模块 模块是编写代码的区域。如下图中&#xff0c;这是一个新的工作簿&#xff0c;因此没有任何模块。 要插入模块&#xff0c;请导航到插…

Cell--瘤内微生物将开辟新疗法

2023年4月13日&#xff0c;弗雷德哈钦森癌症中心的微生物学家Susan Bullman教授在《Cell》杂志发表了关于肿瘤内微生物群的评论。 微生物群是肿瘤微环境的一个组成部分 在患者的肿瘤内部&#xff0c;恶性细胞处在一个复杂的生态系统中&#xff0c;周围是正常细胞的网络&#xf…

socks5与http代理如何转化?stormproxies怎么解决?

Socks5和HTTP代理之间可以通过一些工具或软件进行转化&#xff0c;具体的方法如下&#xff1a; 使用ProxyCap&#xff1a;ProxyCap是一款常用的代理工具&#xff0c;可以将Socks5代理转化为HTTP代理。在ProxyCap中设置Socks5代理的服务器地址和端口&#xff0c;然后在本地设置H…

Java应用高性能的方法和思路

Java应用高性能的方法和思路 目录概述需求&#xff1a; 设计思路实现思路分析 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,challenge …

软件测试基础概念

1.软件测试的生命周期 需求分析-》测试计划-》测试设计-》测试开发-》测试执行-》测试评估 需求分析&#xff1a;分析需求是否合理和正确 计划:确定软件由谁测试&#xff1f; 什么时候开始测试&#xff0c;什么时候结束测试 测试那些模块 测试设计和测试开发阶段&#xff1a;…