浏览器🧑💻 浏览器的渲染流程
DOM 的回流(Reflow)
-
元素的 大小 或者 位置 发生了变化(当页面布局和几何信息发生变化的时候),触发了重新布局,导致渲染树重新计算布局和渲染,如:
- 添加或删除可见的 DOM 元素;
- 元素的位置发生变化;
- 元素的尺寸发生变化;
- 内容发生变化 (比如文本变化或图片被另一个不同尺寸的图片所替代);
- 页面一开始渲染的时候 (这个无法避免);
- 因为回流是根据视口的大小来计算元素的位置和大小的,所以浏览器的窗口尺寸变化也会引发回流…
-
reflow 非常耗时,浏览器为了提升性能,对 JS 中 连续 导致 reflow 的代码,把 reflow 的时间点延迟到结束后进行,但在此过程中,如果遇到了获取尺寸和位置的代码,浏览器会迫不得已立即 reflow;
-
如何避免 DOM 的回流:
- 放弃传统操作 dom 的时代,基于 vue/react 开始数据影响视图模式,mvvm、mvc、virtual dom、dom diff 等;
- 分离读写操作(现代的浏览器都有渲染队列的机制);
//(1) let box = document.getElementById('box'); box.style.width = '200px'; box.style.height = '200px'; box.style.margin = '10px'; // 因为浏览器存在渲染队列机制,如果引发回流的语句挨在一起写,只会引发一次回流 // (2) box.style.width = '100px' box.style.height = '200px' box.clientHeight; // 读取高度,导致强行 reflow box.style.left = '10px' box.style.top = '10px' // 中间插入非引发回流语句,打断了任务队列,所以总共回流 2 次
- 样式集中改变;
- 缓存布局信息 (不要频繁读取 dom,会导致强制回流 Reflow);
- 元素批量修改;
// 1. 文档碎片 createDocumentFragment let frag = document.createDocumentFragment(); for (let i = 0; i < 10; i++) { let span = document.createElement('span'); frag.appendChild(span); } navBox.appendChild(frag); // 2. 模板字符串拼接 let str = ``; for (let i = 0; i < 10; i++) { str += `<span></span>`; } navBox.innerHTML = str;
DOM 的重绘(Repaint)
浏览器一边 reflow,一边进行生成对应的图形绘制到页面,绘制的过程称之为 repaint;
所有会导致 reflow 的代码,均会导致 repaint
绘制的过程是靠 GPU 完成的,速度非常快,因此 相对于导致 reflow 的代码,repaint 的代码效率会高出很多
凡是不会影响盒子排列,仅影响盒子外观的代码都不会导致 reflow,仅导致 repaint,例如:
- 改变背景颜色
- 改变字体颜色
- 圆角边框
- 背景图
- …
剑指 Offer 46.把数字翻译成字符串
上一篇