这是我参与更文挑战的第2天,活动详情查看: 更文挑战
性能优化是什么?百度百科释义:在不影响系统运行正确性的前提下,使之运行地更快,完成特定功能所需的时间更短。
为什么要性能优化?
从用户角度而言,优化能够让页面加载的更快、对用户的操作响应的更及时,能够给用户提供更为友好的体验。
从服务商角度而言,优化能够减少页面请求数、减轻服务器压力,能够节省可观资源。
浏览器的功能与组成
浏览器应该有的功能
网络
浏览器通过网络模块来下载各式各样的资源,例如 html
文本;javascript
代码;样式表;图片;音视频文件等。网络部分本质上十分重要,因为它耗时长,而且需要安全访问互联网上的资源。
资源管理
从网络下载,或者本地获取到的资源需要有高效的机制来管理它们。例如如何避免重复下载,资源如何缓存等。
网页浏览
这是浏览器的核心也是最基本的功能,最重要的功能。如何将资源转变为可视化的结果。
其他
还有多页面管理、插件与管理、账户和同步、安全机制、开发者工具等功能。
浏览器的主要功能就是:将用户输入的url转变成可视化的图像。
浏览器内核
在浏览器中有一个最重要的模块,它主要的作用是将页面转变为可视化的图像结果。这个模块就是浏览器内核,通常它也被称为渲染引擎。
- IE → Trident
- Safari → WebKit
- Chrome → WebKit的分支引擎 → Blink
- Opera → >跟Chrome一样
- Firefox → Gecko
进程和线程
进程
程序的一次执行, 它占有一片独有的内存空间.是操作系统执行的基本单元。
- 一个进程中至少有一个运行的线程: 主线程, 进程启动后自动创建;
- 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的;
- 一个进程内的数据可以供其中的多个线程直接共享,多个进程之间的数据是不能直接共享的
线程
进程内的一个独立执行单元,是CPU调度的最小单元,程序运行的基本单元
线程池(thread pool): 保存多个线程对象的容器,以实现线程对象的反复利用。
!!JS引擎是单线程运行的!!
现代浏览器的多进程多线程模型
1 不堪回首的过去
当你通过浏览器打开很多页面的时候,如果其中一个页面不响应了或者崩溃了,那么随之而来的将会是更不幸的事情,你开打的所有页面都会得不到响应,最让人不能忍受的是,其中的一些页面可能还包含了未保存或者未发送的信息。
2 浏览器产商如何解决
采用多进程模型,该模型带来的好处:
- 避免因单个页面的不响应或者崩溃影响整个浏览器的稳定性
- 当第三方插件崩溃时,也不会影响整个浏览器的稳定性
- 安全
3 浏览器有哪些进程
Browser进程
浏览器的主进程,负责浏览器界面的显示,和各个页面的管理,浏览器中所有其他类型进程的祖先,负责其他进程的的创建和销毁。有且只有一个!!
Renderer进程
网页渲染进程,负责页面的渲染,可以有多个。渲染进程的数量不一定等于你开打网页的个数。
VUE插件进程、React插件进程、GPU进程等
4 每个进程内部又有很多线程
多线程的目的主要是保持用户界面的高度响应
渲染引擎&阻塞
浏览器渲染引擎
主要模块
一个渲染引擎主要包括:HTML
解析器、CSS
解析器、JavaScript
引擎、布局 layout
模块、绘图模块。
HTML
解析器:解析HTML
文档,将HTML
文本解释成DOM
树CSS
解析器:级联样式表的解析器,为DOM
中的各个元素对象计算出样式,为布局提供基础设施JavaScript
引擎:使用JavaScript
代码可以修改网页的内容,也能修改CSS
的信息,JavaScript
引擎可以解释JavaScript
代码,并通过DOM
接口和CSSOM
接口修改网页的内容和样式,从而改变渲染的结果。- 布局
layout
:DOM
创建后,Webkit
需要将其中的元素对象同样式信息结合起来,计算他们的大小位置等布局信息,形成一个能表达这所有信息的内部表示模型 - 绘图模块(paint):使用图形库将布局计算后的各个网页的节点绘制成图像结果
渲染过程
浏览器会从上到下解析文档。
- 遇到
HTML
标记,调用HTML
解析器解析,并构建DOM
树 - 遇到
style/link
标记,调用CSS
解析器解析,并构建CSSOM
树 - 遇到
script
标记,调用JavaScript
解析器处理,绑定事件,修改DOM/CSSOM
树等 - 将
DOM
与CSSOM
合并成一个渲染树 - 根据渲染树来布局,以计算每个节点的几何信息
- 将各个节点绘制到屏幕上
阻塞渲染
CSS 阻塞
1、 style 标签中的样式
- 由
HTML
解析器进行解析 - 不阻塞浏览器渲染
- 不阻塞
DOM
解析
2、 link 引入的外部 css 样式
- 由
css
解析器进行解析; - 阻塞浏览器渲染(避免闪屏)
- 不阻塞
DOM
结构解析(DOM
解析和CSS
解析是两个并行的进程) - 外部的
css
加载会阻塞后面js
语句的执行(js
有可能会改变css
的属性)
3、 为什么推荐使用 <link>
方式引入外部 css
?
- 可以避免闪屏现象
4、 优化方案:尽可能的提高 css
加载速度
- 使用
CDN
加速 - 对
css
文件进行压缩 - 减少
http
请求数,将多个文件合并为一个
JS 阻塞
1、 阻塞 DOM
解析
2、 阻塞页面渲染
3、 阻塞后续 js
逻辑的执行,但是不阻塞 js
等其他资源的加载
!!css
的解析和 js
的执行是互斥的!!
图层 & 重绘重排
css 图层
在渲染 DOM 的时候,浏览器所做的工作是:
- 获取 DOM 后分割为多个图层
- 对每个图层的节点计算样式结果
- 为每个节点生成图形和位置
- 将每个节点绘制填充到图层位图中
- 图层作为纹理上传至 GPU
- 多个图层到页面上生成最终屏幕图案
图层创建的条件
- 拥有具有 3D 变换的 CSS 属性
- 使用加速视频解码的 节点
- 节点
- CSS3 动画的节点
- 拥有 CSS 加速属性的元素(
will-change
)
重绘
重绘是一个元素外观的改变所触发的浏览器行为,重绘是以图层为单位,如果图层中某个元素需要重绘,那么整个图层都需要重绘。
触发重绘的属性:color
、background
、outline-color
、border-style
、background-image
、outline
、border-radius
、background-position
、outline-style
、visibility
、background-repeat
、outline-width
、text-decoration
、background-size
、box-shadow
重排
渲染对象在创建完成并添加到渲染树时,并不包含位置和大小信息。计算这些值的过程称为布局或重排。
触发重排的属性
- 盒子模型相关属性会触发重排(width、height、padding、margin、display、border-width、border、min-height)
- 定位属性以及浮动会触发重排(top、bottom、left、right、position、float、clear)
- 改变节点内部文字结构也会触发重排(text-align、overflow-y、font-weight、overflow、font-family、line-height、vertical-align、white-space)
“重绘”不一定需要“重排”;但是,“重排”必然导致“重绘”。
触发重绘重排的操作
- 当你增加、删除、修改 DOM 结点时,会导致 Reflow , Repaint
- 当你移动 DOM 的位置
- 当你修改 CSS 样式的时候
- 当你 Resize 窗口的时候
- 当你修改网页的默认字体时
- 获取某些属性时(
width
,height
…)
优化方案
1、 元素位置移动变换时尽量使用 CSS3 的 transform
来代替对 top
left
等的操作
变换(transform
)和透明度(opacity
)的改变仅仅影响图层的组合
2、 使用 opacity
来代替 visibility
- 使用
visibility
不触发重排,但是依然重绘。 - 直接使用
opacity
即触发重绘,又触发重排。 opacity
配合图层使用,即不触发重绘也不触发重排。
3、 不要使用 table
布局
4、 将多次改变样式属性的操作合并成一次操作
不要一条一条地修改 DOM
的样式,预先定义好 class
,然后修改 DOM
的 className
5、 将 DOM 离线后再修改
由于 display
属性为 none
的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发2次重排。
6、 利用文档碎片(documentFragment
)
7、 不要把某些 DOM 节点的属性值放在一个循环里当成循环的变量
8、 动画实现过程中,启用 GPU 硬件加速:transform: tranlateZ(0)
9、 为动画元素新建图层,提高动画元素的 z-index
缓存
缓存理解
定义:浏览器在本地磁盘上将用户之前请求的数据存储起来,当访问者再次需要修改数据的时候无需再次发送请求,直接从浏览器本地获取。
好处:减少请求的个数;节省带宽,避免浪费不必要的网络资源;减轻服务器压力;提高浏览器网页的加载速度,提高用户体验。
缓存分类
强缓存
不会向服务器发送请求,直接从本地缓存获取数据;请求资源的状态码为200 ok(from memory cache)。
协商缓存
向服务器发送请求,服务器会根据请求头的资源判断是否命中协商缓存,如果命中,则返回 304 状态码通知浏览器从缓存中请求资源。
共同点
都是从浏览器端读取资源
不同点
强缓存不发送请求给服务器;协商缓存发请求给服务器,根据服务器返回的信息决定是否使用缓存。
浏览器存储
cookie、SessionStorage、LocalStorage这三者都可以被用来在浏览器端存储数据,而且都是字符串类型的键值对!(另外还有一种存储模式叫:session;这种级别的存储属于服务端会话级别的存储)
cookie
cookie 是什么?
cookie是纯文本格式,不包含任何可执行的代码信息,伴随着用户请求在 Web 服务器和浏览器之间传递。cookie本质上属于http的范畴,因为http协议本身是无状态的,服务端是没有办法区分请求来自于哪个客户端,即便是来自于同一个客户端的多次请求我们的服务端也是没有能力来区分的。就是因为http协议是无状态的,所以才需要cookie去维持客户端的状态。
cookie 的生成方式
客户端生成
在 JavaScript
中通过 document.cookie
属 性,可以创建、维护和删除 cookie
,设置 document.cookie
属性的值并不会删除存储在页面中的所有 cookie
。它只简单的创建或修改字符串中指定的 cookie
;要使用 JavaScript
提取 cookie
的值,只需要从 document.cookie
中读取即可。
服务端生成
Web 服务器通过发送一个称为 Set-Cookie
的 HTTP消息头来创建一个 cookie;为避免跨域脚本 (XSS) 攻击,通过JavaScript的 Document.cookie API
无法访问有 HttpOnly 标记的cookie。
cookie 的缺点
安全性:由于 cookie 在 HTTP 中是明文传递的,其中包含的数据都可以被他人访问,可能会被篡改、盗用。
大小限制:cookie 的大小限制在 4KB 左右,若要做大量存储显然不是理想的选择。
增加流量: cookie 每次请求都会被自动添加到 Request Header 中,无形中增加了流量。cookie 信息越大,对服务器请求的时间也越长。因此要慎用 cookie,不要在 cookie 中存储重要和敏感的数据。
Web Storage
SessionStorage 和 LocalStorage 都是本地存储,不会被发送到服务器上。同时空间比Cookie 大很多,一般支持 5-10M;浏览器端通过 Window.sessionStorage
和 Window.localStorage
属性来实现本地存储机制。
// 接受一个键名作为参数,返回键名对应的值。
var data = Storage.getItem('key');
// 接受一个键名和值作为参数,将会把键值对添加到存储中,如果键名存在,则更新其对应的值。
Storage.setItem('key', 'value');
// 接受一个键名作为参数,并把该键名从存储中删除。
Storage.removeItem('key');
// 调用该方法会清空存储中的所有键名
Storage.clear()
复制代码
storage事件:
Storage 对象发生变化时会触发在同一个页面内发生的改变不会起作用,在相同域名下的其他页面发生的改变才会起作用。(修改的页面不会触发事件,与它共享的页面会触发事件)
key // 修改或删除的key值,如果调用clear(),为null
newValue // 新设置的值,如果调用clear(),为null
oldValue // 调用改变前的value值,如果调用clear(),为null
url // 触发该脚本变化的文档的url
storageArea // 当前的storage对象
复制代码
最后说一句
如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下,您的支持是我坚持写作最大的动力,多谢支持。