由defer、async区别面试题产生的联想(二)

160 阅读3分钟

五、重排、重绘及浏览器优化策略

1、回流(Reflow):

回流的代价要远大于重绘。并且回流必然会造成重绘,但重绘不一定会造成回流。

当渲染树Render Tree中的一部分因为元素的规模尺寸布局隐藏等改变需要重新构建。这就称为回流。每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是一定会发生回流的,因为要构建render tree。

2、重绘(Repaint):当渲染树render tree中的一些元素需要更新样式,但这些样式属性只是改变元素的外观,而不会影响布局的,就叫称为重绘(repaint)

会导致回流的操作:

  • 页面首次渲染(无法避免且开销最大的一次)

  • 浏览器窗口大小发生改变(resize事件)

  • 元素尺寸或位置发生改变(边距、宽高、边框等)

  • 元素内容变化(文字数量或图片大小等等)

  • 元素字体大小变化(font-size)

  • 添加或者删除可见DOM元素

  • 查询某些属性或调用某些方法(getBoundingClientRect、offsetTop)

查询某些属性或调用某些方法都需要返回最新的布局信息,因此浏览器不得不触发回流重绘来返回正确的值。

会导致重绘的属性:

color、visibility、background等等

display:none触发回流;

visibility:hidden触发重绘;

opacity:0是在合成层,效率最高

浏览器优化策略:

由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才会进行批量修改并清空队列。但是,在获取布局信息的时候,会强制刷新队列

开发者优化策略:

【1】避免频繁操作DOM元素

【2】设置DOM元素的display属性为none再操作该元素

【3】合并多次DOM操作

六、图片懒加载

原理其实非常简单,主要就是需要判断元素是否进入了可视区,进入了可视区就去请求对应的图片,否则就显示一张兜底的占位图。

【1】早前实现思路:(Element.getBoundingClientRect方法:本质是同步检测,会影响用户scroll性能)

  • 给目标元素指定一张占位图,将真实的图片链接存储在自定义属性中,通常是data-src;

  • 监听与用户滚动行为相关的 scroll 事件(用防抖、节流限制,但还是会影响性能);

  • 在 scroll 事件处理程序中利用 Element.getBoundingClientRect() 方法判断目标元素与视口的交叉状态

  • 当目标元素与视口的交叉状态大于0时,将真实的图片链接赋给目标元素 src 属性或者 backgroundImage 属性。

  • getBoundingClientRect还会触发回流

【2】现在实现思路:(IntersectionObserver 接口,异步监听交叉状态,不随着用户scroll同步触发,不影响滚动性能)

七、判断图片是否进入视窗

【1】getBoundingClientRect