浏览器渲染原理与性能优化
HTML、CSS渲染过程
DOM构建过程:字符数据->字符串->Token(标记)->Node->DOM树
CSSOM构建过程:字符数据->字符串->Token(标记)->Node->CSSOM树
DOM树和CSSOM树组合为渲染树
display:none 不会在渲染树中显示
为什么操作DOM慢?
DOM树属于渲染引擎,JS属于JS引擎,操作DOM树要在两个引擎的线程之间通信
插入大数据量DOM节点,如何做到不卡顿?
方式1:采用requestAnimation循环插入DOM
方式2:虚拟滚动,只展示用户看到的DOM
什么情况阻塞渲染?
当浏览器解析到script标签,会暂停DOM构建,进行脚本下载和解析,完成后继续构建DOM
解决方式:
重绘(repaint)和回流(reflow)
- 重绘指当节点需要改变外观但是不会影响布局时发生,比如color
- 回流指当节点的几何属性会布局变化时发生
重绘不一定引起回流,但是回流一定会引发重绘,所以 回流的成本大于重绘
以下几点需要注意:
- 改变window大小
- 改变字体
- 添加、删除、修改样式
- 文字改变
- 定位或者浮动
- 盒模型改变
重绘回流与EventLoop关系
- 当 Eventloop 执行完 Microtasks 后,会判断
document
是否需要更新,因为浏览器是 60Hz 的刷新率,每 16.6ms 才会更新一次。 - 然后判断是否有
resize
或者scroll
事件,有的话会去触发事件,所以resize
和scroll
事件也是至少 16ms 才会触发一次,并且自带节流功能。 - 判断是否触发了 media query
- 更新动画并且发送事件
- 判断是否有全屏操作事件
- 执行
requestAnimationFrame
回调 - 执行
IntersectionObserver
回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好 - 更新界面
- 以上就是一帧中可能会做的事情。如果在一帧中有空闲时间,就会去执行
requestIdleCallback
回调。
减少重绘和回流
- 使用transform
- visibility 代替 display:none ,前者引起重绘,后者引起回流
- 不要在循环中获取节点offsetTop等属性(会导致回流)
- 不要使用table布局,小改动会引发整个table回流
- 动画实现速度越快,回流越多,使用requestAnimationFrame
- 将频繁重绘或者回流的节点设置为图层
设置为图层的方法:
- will-change
- 使用video、iframe
总结
在不考虑缓存和优化网络协议的前提下,考虑可以通过哪些方式来最快的渲染页面,也就是常说的 关键路径渲染,这部分也是性能优化中的一块内容
提前DOMContentLoaded时间发生时间,该时间发生后就会生成渲染树渲染,与硬件关系较大,优化空间小
解决方向:
- 从文件大小考虑
- 从script标签考虑
- 从Html,css代码书写考虑
- 从需要下载的内容是否在首屏上使用考虑
css从右向左解析,因此css需要扁平化。html嵌套层级不应该太多,减少嵌套层级
使用 Verdaccio 搭建私有 npm 服务
为什么要搭建npm私服?
假如我们由于平时的技术积累,写了一些可以复用的工具,我们想分享给公司其它同事使用;或者我们公司可能会有一个公共组件仓库,我们想用npm的方式安装而不是去简单的拷贝文件;然而,这些工具或者组件都涉及公司内部的机密,这时我们就可以搭建一个npm私服,只在公司局域网访问,我们可以将我们写好的工具发布到上面,方便其它同事安装使用。当访问到本地npm没有的包时,verdaccio会根据设置的远程仓库路径下载(远程仓库可以通过配置文件修改),之后将下载完成的包缓存到本地,当下一次安装同样的包时就可以直接从本地缓存获取了。
为什么要选verdaccio?
目前,市面上用来搭建npm私服的工具有大体三种:
- nexus
- cnpm
- verdaccio
nexus功能强大,但是部署和配置较繁琐,不符合我们的使用要求。cnpm虽然比nexus配置简单,但是也需要使用到mysql。有没有更好用的工具呢?那就是verdaccio。verdaccio使用文件存储包数据,无需安装数据库并且部署简单,只需要一行代码就可以部署完成,这个正是我们需要的。
verdaccio部署
首先,假设我们已经在服务器端安装了nodejs和npm。下面我们来讲讲verdaccio的部署。1
2
3
4
5
6
7
8# 安装
npm install -g verdaccio
## 初始化
verdaccio --init ~/verdaccio.config.js
## 运行verdaccio
verdaccio
下面我们用浏览器访问 http://localhost:4873,如果我们看到这样的界面,说明我们已经部署成功。
使用pm2启动
pm2 是一款著名的nodejs进程守护和管理工具,下面我们用pm2来启动verdaccio:1
2# 使用pm2启动
pm2 start verdaccio
启动成功后会输出以下内容
使用
为了方便切换npm仓库地址,我们使用nrm。首先,我们来安装nrm。1
npm install -g nrm
下面,我们使用nrm管理npm仓库原地址,我们使用verdaccio地址。
1 | nrm add local http://localhost:4873 # 添加远程仓库源 |
这样,我们就成功将npm的仓库地址换成了我们最新搭建的私服地址。🍺
发布包
在发布包之前,我们首先需要新建用户。1
2
npm adduser
在输入用户名、密码和邮箱后,我们成功在我们本地的npm私服创建了用户。
下面我们来发布一个npm包:
1 | npm publish <npm_pkg_name> |
总结
在我们发布完成后,包的内容会显示在网页上,这样我们就完成来verdaccio的基本使用操作。下次使用这个包的时候,我们可以直接运行npm install
,由于之前我们已经使用nrm修改了仓库源的地址,所以npm会从我们刚搭的私服上面获取对应的包文件,这样我们就可以愉快的在局域网私服上面发布自己写的包了~