浏览器知识零散学习

235 阅读8分钟

浏览器渲染过程

  1. 解析HTML,生成DOM树,解析CSS,生成CSSOM树。
  2. 将DOM树和CSSOM树结合,生成渲染树(Render Tree)。
  3. Layout(回流):根据生成的渲染树,进行回流,得到节点的几何信息(位置,大小)
  4. Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
  5. Display:将像素发送给GPU,展示在页面上

生成渲染树

  1. 从DOM树的根节点开始遍历每个可见节点
  2. 对于每个可见的节点,找到CSSOM树中对应的规则,并应用它们。
  3. 根据每个可见节点以及其对应样式,组合生成渲染树。

注意:渲染树只包含可见的节点。 不可见节点:不会渲染输出的节点,比如script meta link等。还有通过css隐藏的节点比如display:none

回流(reflow)

通过构造渲染树,将可见DOM节点以及它对应的样式结合起来,然后计算节点在设备视口的确切位置和大小。这个计算阶段就是回流。

重绘(repaint)

通过构造渲染树和回流阶段,已知可见节点的样式和具体的几何信息(位置,大小),将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。

何时发生回流重绘

回流阶段主要计算节点位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流。比如以下情况:

  • 添加/删除可见DOM元素
  • 元素位置发生变化
  • 元素尺寸发生了变化(边距、边框、宽高等)
  • 内容发生变化,比如文本变化,图片变化
  • 浏览器尺寸发生变化。(回流是根据视口的大小来计算元素的位置和大小的)

注意:回流一定会触发重绘,重绘不一定触发回流。

如何减少回流和重绘?

  1. 最小化回流和重绘 合并多次对DOM的修改 比如:
let el = document.getElementById("root")
el.width = "100px";
el.height = "100px";
el.padding = "10px";

以上代码对于元素进行了多次修改,理论上每一次修改都会引起一次回流,以上修改了三次因此三次回流,但是大部分现代浏览器都做了优化,只会引起一次回流,但是在旧版本浏览器中还是会引起三次回流。

因此可以考虑合并所有修改统一处理

let el = document.getElementById("root");

el.style.cssText += `el.width = 100px;el.height = 100px;el.padding = 10px;`

或者

let el = document.getElementById("root");
el.className += 'active'
  1. 批量修改DOM 当对DOM进行一系列修改的时候,可以通过以下步骤减少回流重绘次数。 (1). 使元素脱离文档流 (2). 对元素进行操作 (3). 让元素回归文档流 按照这个步骤操作。1,3两步会引起回流,但是频繁操作的第二步却是不会引起回流的,因为目标元素已经不在渲染树了。 有三种方式可以让DOM脱离文档流:
  • 隐藏元素,修改,重新显示
  • 使用文档片段(document fragment)在当前DOM之外构建一个子树,再把它拷贝回文档。
  • 将原始元素拷贝到一个脱离文档的节点中,修改节点再替换原始元素。
var ul = document.getElementById("root");
for (var i = 0; i<3; i++){
  var li = document.createElement('li');
  li.innerText = "text"
  ul.appendChild(li)
}

以上代码回流三次 以下是优化方案

var ul = document.getElementById("root");
ul.style.display = "none"
for (var i = 0; i<3; i++){
  var li = document.createElement('li');
  li.innerText = "text"
  ul.appendChild(li)
}
ul.style.display = "block"

回流2次

var ul = document.getElementById("root");
var frag = document.createDocumentFragment();
for (var i = 0; i<3; i++){
  var li = document.createElement('li');
  li.innerText = "text"
  frag.appendChild(li)
}
ul.appendChild(frag)
var ul = document.getElementById("root");
var clone = ul.cloneNode(true);
for (var i = 0; i<3; i++){
  var li = document.createElement('li');
  li.innerText = "text"
  clone.appendChild(li)
}
ul.parentNode.replaceChild(clone,ul)

理论上是可以优化的,但是现代浏览器实际上会使用队列来存储多次修改,进行优化,所以在现代浏览器上优化效果不明显。

  1. 对于动画可以使用绝对定位使其脱离文档流,避免影响父元素后续频繁回流。

  2. CSS3硬件加速(GPU加速)

css3硬件加速可以让transform、opacity、filters、这些动画不会引起回流重绘。 常见触发硬件加速css属性

缺点:硬件加速过多会导致内存过大,会有性能问题。

参考: 你真的了解回流和重绘吗

浏览器数据本地存储

localStorage

生命周期永久,除非用户清除浏览器中的localStorage信息,否则永远存在; localStorage中一般浏览器支持的是5M大小 优点:

  • 拓展了cookie的4k限制
  • 遵循同源策略,不同的网站直接不能使用相同的localStorage 缺点:
  • 需要手动删除,否则长期存在
  • 各浏览器支持不太统一
  • 只支持String类型的存储,JSON对象须使用JSON.stringify()转换
  • 本质是对字符串的读取,如果存储内容多会消耗内存,导致页面变卡

sessionStorage

会话存储,在浏览器被关闭之前使用,关闭浏览器之后数据消失。(关闭当前页面不会消失,再次打开该页面,sessionStorage还存在)

Cookie

Cookie主要由服务端生成,前端也可以设置,保存在客户端本地,通过response响应头的set-Cookie字段进行设置,且Cookie的内容自动在请求的时候被传递给服务器。 如下:

Cache-Control: max-age=0, private, must-revalidate
Connection: keep-alive
Date: Mon, 25 May 2020 09:09:03 GMT
ETag: W/"b9e6480ac475b399cd9533cab4fa89ce"
Server: Tengine
Set-Cookie: locale=zh-CN; path=/
Set-Cookie: _m7e_session_core=1c249e10b2aaad51dcbe0aa865cf3f34; domain=.jianshu.com; path=/; expires=Mon, 25 May 2020 15:09:03 -0000; secure; HttpOnly
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Request-Id: 9b702ad0-88f3-4b48-8e43-48d971c57888
X-Runtime: 0.065999
X-XSS-Protection: 1; mode=block

Cookie格式如下

Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnly;secure"

其中name=value是必选项,其他都是可选项。 主要构成如下:

name:一个唯一确定的cookie名称。

value:存储在cookie中的字符串值,一般情况下都会进行加密编码

domin:指明cookie对哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域(如:domain=.jianshu.com则表示对于jianshu.com的所有子域都有效)

path:表示这个cookie影响到的路径,浏览器会根据这项配置向指定域中匹配的路径发送cookie

expires:失效时间,表示cookie何时应该删除的时间戳(也就是,何时停止向服务器发送该cookie)。如果不设置,浏览器会在页面关闭时删除所有cookie;不过也可以自己设置删除时间。这个值是GMT格式,如果客户端和服务器端时间不一致,使用expires就会存在偏差。

max-age:与expires的作用相同,用来告诉浏览器此cookie多久过期(单位:秒)而不是一个固定的时间点。正常情况下,max-age的优先级高于expires。

HttpOnly告知浏览器不允许通过脚本document.cookie去更改这个值,同样这个值在doucment.cookie中也不可见,但在http请求中仍然会携带这个cookie,虽然在脚本中不可获取,但仍然在浏览器安装目录中以文件形式存在。这项通常在服务器端设置。

secure:安全标志,制定后只有在使用SSL链接时候才能发送的浏览器,如果是http链接则不会传递该信息。就算设置了secure属性也并不代表他人不能看到机器本地保存的cookie信息,所以不要把重要信息放cookie就对了。

Cookie作用: 可以记录用户ID、密码、浏览过的网页、停留的时间等信息。一个网站只能读取它自己放置的信息,不能读取其他网站的Cookie文件。因此,Cookie文件还保存了host属性,即网站的域名或ip。这些属性以键值对的方式保存,为了安全,内容大多加密处理。 Cookie优点:

  • 提升用户体验,如记住密码等功能
  • 弥补了HTTP无连接特性
  • 站点统计访问人数的一个依据

Cookie缺点:

  • 无法解决多人共用一台电脑的问题,有不安全因素。
  • Cookie文件容易被误删
  • 容量有限制
  • 在请求头上携带存在数据安全性问题
  • Cookies欺骗,修改host文件,可以非法访问目标站点的Cookie

indexDB

浏览器发展越来越成熟,很多应用考虑做离线功能,将大量数据存储在客户端,这样可以减少从服务器获取数据,直接从本地获取数据。 由于存储空间大小和其他原因,浏览器的存储方案都不适合做大量数据存储。 IndexDB就是浏览器提供的本地数据库,可以被网页脚本创建,操作。允许存储大量数据,提供查找接口,建立索引等。浏览器数据库 IndexedDB 入门教程

写在最后:文中内容大多为自己平时从各种途径学习总结,文中参考文章大多收录在我的个人博客里,欢迎阅览www.tianleilei.cn