# 1 跨标签页通讯
不同标签页间的通讯,本质原理就是去运用一些可以 共享的中间介质,因此比较常用的有以下方法:
- 通过父页面
window.open()和子页面postMessage- 异步下,通过
window.open('about: blank')和tab.location.href = '*'
- 异步下,通过
- 设置同域下共享的
localStorage与监听window.onstorage- 重复写入相同的值无法触发
- 会受到浏览器隐身模式等的限制
- 设置共享
cookie与不断轮询脏检查(setInterval) - 借助服务端或者中间层实现
# 2 浏览器架构
- 用户界面
- 主进程
- 内核
- 渲染引擎
JS引擎- 执行栈
- 事件触发线程
- 消息队列
- 微任务
- 宏任务
- 消息队列
- 网络异步线程
- 定时器线程
# 3 渲染机制
# 3.1 浏览器的渲染机制一般分为以下几个步骤
- 处理
HTML并构建DOM树。 - 处理
CSS构建CSSOM树。 - 将
DOM与CSSOM合并成一个渲染树。 - 根据渲染树来布局,计算每个节点的位置。
- 调用
GPU绘制,合成图层,显示在屏幕上

- 在构建 CSSOM 树时,会阻塞渲染,直至 CSSOM 树构建完成。并且构建 CSSOM 树是一个十分消耗性能的过程,所以应该尽量保证层级扁平,减少过度层叠,越是具体的 CSS 选择器,执行速度越慢。
- css 是阻塞渲染的资源。需要将它尽早、尽快地下载到客户端,以便缩短首次渲染的时间
- 当 HTML 解析到 script 标签时,会暂停构建 DOM,完成后才会从暂停的地方重新开始。也就是说,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件。并且 CSS 也会影响 JS 的执行,只有当解析完样式表才会执行 JS,所以也可以认为这种情况下,CSS 也会暂停构建 DOM
# 3.2 图层
一般来说,可以把普通文档流看成一个图层。特定的属性可以生成一个新的图层。不同的图层渲染互不影响,所以对于某些频繁需要渲染的建议单独生成一个新图层,提高性能。但也不能生成过多的图层,会引起反作用
- 通过以下几个常用属性可以生成新图层
3D变换:translate3d、translateZwill-changevideo、iframe标签- 通过动画实现的
opacity动画转换 position: fixed
# 3.3 重绘与回流
当元素的样式发生变化时,浏览器需要触发更新,重新绘制元素。这个过程中,有两种类型的操作,即重绘与回流。
- 重绘(repaint): 当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要UI层面的重新像素绘制,因此 损耗较少
- 回流(reflow): 当元素的尺寸、结构或触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。会触发回流的操作:
- 页面初次渲染
- 浏览器窗口大小改变
- 元素尺寸、位置、内容发生改变
- 元素字体大小变化
- 添加或者删除可见的
dom元素 - 激活
CSS伪类(例如::hover) - 查询某些属性或调用某些方法
clientWidth、clientHeight、clientTop、clientLeftoffsetWidth、offsetHeight、offsetTop、offsetLeftscrollWidth、scrollHeight、scrollTop、scrollLeftgetComputedStyle()getBoundingClientRect()scrollTo()
回流必定触发重绘,重绘不一定触发回流。重绘的开销较小,回流的代价较高。
回流的优化
对树的局部甚至全局重新生成是非常耗性能的,所以要避免频繁触发回流
- 现代浏览器已经帮我们做了优化,采用队列存储多次的回流操作,然后批量执行,但获取布局信息例外,因为要获取到实时的数值,浏览器就必须要清空队列,立即执行回流。
- 编码上,避免连续多次修改,可通过合并修改,一次触发
- 减少
dom的增删次数,可使用 字符串 或者documentFragment一次性插入 - 对于大量不同的
dom修改,可以先将其脱离文档流,比如使用绝对定位,或者display:none,在文档流外修改完成后再放回文档里中 - 将动画效果应用到
position属性为absolute或fixed的元素上 - 动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用
requestAnimationFrame - 通过节流和防抖控制触发频率
css3硬件加速,transform、opacity、filters,开启后,会新建渲染层
另外,可以借助 DevTools Performance 面板来查看产生回流重绘任务占用主线程的情况和调用代码
开启GPU加速的方法
开启后,会将 dom元素提升为独立的渲染层,它的变化不会再影响文档流中的布局。
transform: translateZ(0)opacityfiltersWill-change
很多人不知道的是,重绘和回流其实和 Event loop 有关
- 当
Event loop执行完Microtasks后,会判断document是否需要更新。因为浏览器是60Hz的刷新率,每16ms才会更新一次。 - 然后判断是否有
resize或者scroll,有的话会去触发事件,所以resize和scroll事件也是至少16ms才会触发一次,并且自带节流功能。 - 判断是否触发了
media query - 更新动画并且发送事件
- 判断是否有全屏操作事件
- 执行
requestAnimationFrame回调 - 执行
IntersectionObserver回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好 - 更新界面
