标签:优化 使用 硬件 简单的 script 浏览器渲染 展示 aci 加载
渲染机制:几个概念,没有代码。一般会问:
1、什么是DOCTYPE以及作用。
2、浏览器渲染过程。有的公司会问:浏览器中输入url,发生哪些事情,让你一步一步描写清楚?其中有一步就是浏览器渲染过程。输入url,会有一个dms解析,然后发到服务器,服务器再响应,响应过来,到了客户端,浏览器这边就开始渲染过程。
3、重排Reflow
4、重绘Repaint
5、布局Layout 这个和css布局不同,这个是浏览器的布局方式。这五个大概念,弄清楚。
DTD告诉浏览器,我是什么文档类型。浏览器根据这个来判断用什么浏览引擎来解析它渲染它。
DOCTYPE 就是直接告诉浏览器什么是DTD。告诉浏览器包含哪个DTD,也就是哪个文档类型。
常见的DOCTYPE 有哪些?写一下HTML5的DOCTYPE怎么写?
要会写HTML5 的文档类型声明
然后知道HTML4.01有严格模式和传统模式,严格模式不包含展示性元素或弃用元素,如 <font>
浏览器的渲染机制一般分为以下几个步骤
补充 render tree不包含html具体内容,也不知道具体位置是什么。比如有一个div,layout之前,不知道画在具体什么位置。这时候通过layout就可以精确计算到要显示的这些dom真正的宽高,位置颜色,最后开始paint,画图,把内容呈现出来。最后display,在浏览器上能看到页面效果
为了形成渲染树,浏览器大致做的事情有:从DOM树根节点开始,遍历每一个可见的节点一些节点是完全不可见的(比如 script标签,meta标签等),这些节点会被忽略,因为他们不会影响渲染的输出一些节点是通过CSS样式隐藏了,这些节点同样被忽略——例如如果 span样式是display:none;
span节点在render tree中被忽略,因为对每一个可见的节点,找到合适的匹配的CSSOM规则,并且应用样式显示可见节点(节点包括内容和被计算的样式)
在构建 CSSOM 树时,会阻塞渲染,直至 CSSOM 树构建完成。并且构建 CSSOM 树是一个十分消耗性能的过程,所以应该尽量保证层级扁平,减少过度层叠,越是具体的 CSS 选择器,执行速度越慢。
(css如果不放在head里,浏览器渲染出html元素后,发现了css,还要重新再渲染,会造成页面卡顿。所以尽量放在头部,一次将DOM树和CSSOM树渲染出来)
当 HTML 解析到 script 标签时,会暂停构建 DOM,完成后才会从暂停的地方重新开始。也就是说,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件。并且 CSS 也会影响 JS 的执行,只有当解析完样式表才会执行 JS,所以也可以认为这种情况下,CSS 也会暂停构建 DOM。
Load 事件触发代表页面中的 DOM,CSS,JS,图片已经全部加载完毕。
DOMContentLoaded 事件触发代表初始的 HTML 被完全加载和解析,不需要等待 CSS,JS,图片加载。
window.addEventListener(‘load‘, ); window.addEventListener(‘DOMContentLoaded‘, )
一般来说,可以把普通文档流看成一个图层。特定的属性可以生成一个新的图层。不同的图层渲染互不影响,所以对于某些频繁需要渲染的建议单独生成一个新图层,提高性能。但也不能生成过多的图层,会引起反作用。
通过以下几个常用属性可以生成新图层
3D 变换:translate3d、translateZ
will-change
video、iframe 标签
通过动画实现的 opacity 动画转换
position: fixed
重绘和回流是渲染步骤中的一小节,但是这两个步骤对于性能影响很大。
重绘是当节点需要更改外观而不会影响布局的,比如改变 color 就叫称为重绘
回流是布局或者几何属性需要改变就称为回流。
回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变深层次的节点很可能导致父节点的一系列回流。
当页面布局和几何属性改变时就需要回流。下述情况会发生浏览器回流:
1、添加或者删除可见的DOM元素;
2、元素位置改变;
3、元素尺寸改变——边距、填充、边框、宽度和高度
4、内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
5、页面渲染初始化;
6、浏览器窗口尺寸改变——resize事件发生时;
var s = document.body.style;
s.padding = "2px"; // 回流+重绘
s.border = "1px solid red"; // 再一次 回流+重绘
s.color = "blue"; // 重绘
s.backgroundColor = "#ccc"; // 重绘
s.fontSize = "14px"; // 再一次 回流+重绘
document.body.appendChild(document.createTextNode(‘abc!‘));// 添加node,再一次 回流+重绘
从上个实例代码中可以看到几行简单的JS代码就引起了6次左右的回流、重绘。而且我们也知道回流的花销也不小,如果每句JS操作都去回流重绘的话,浏览器可能就会受不了。所以很多浏览器都会优化这些操作,浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。
虽然有了浏览器的优化,但有时候我们写的一些代码可能会强制浏览器提前flush队列,这样浏览器的优化可能就起不到作用了。当你请求向浏览器请求一些 style信息的时候,就会让浏览器flush队列,比如:
offsetTop, offsetLeft, offsetWidth, offsetHeight
scrollTop/Left/Width/Height
clientTop/Left/Width/Height
width,height
请求了getComputedStyle(), 或者 IE的 currentStyle // 这个属性表示经过计算过最终的样式,可以参考张鑫旭的博客
当你请求上面的一些属性的时候,浏览器为了给你最精确的值,需要flush队列,因为队列中可能会有影响到这些值的操作。即使你获取元素的布局和样式信息跟最近发生或改变的布局信息无关,浏览器都会强行刷新渲染队列。
减少回流、重绘其实就是需要减少对render tree的操作(合并多次多DOM和样式的修改),并减少对一些style信息的请求,尽量利用好浏览器的优化策略。具体方法有:
// 不好的写法
var left = 1;
var top = 1;
el.style.left = left + "px";
el.style.top = top + "px";
// 比较好的写法
el.className += " className1";
// 比较好的写法
el.style.cssText += ";
left: " + left + "px;
top: " + top + "px;";
#### 把 DOM 离线后修改,
比如:先把 DOM 给 display:none (有一次 Reflow),然后你修改 100 次,然后再把它显示出来
a) 使用DocumentFragment进行缓存操作,引发一次回流和重绘;
复制代码
//不好的写法(模式中所说的反模式)
var p, t;
p = document.creatElement(‘p‘);
t = document.creatTextNode(‘fist paragraph‘);
p.appendChild(t);
document.body.appendChild(p); //将引起一次回流
p = document.creatElement(‘p‘);
t = document.creatTextNode(‘second paragraph‘);
p.appendChild(t);
document.body.appendChild(p); //将再引起一次回流
//好的写法
var p, t, frag;
frag = document.creatDocumentFragment();
p = document.creatElement(‘p‘);
t = document.creatTextNode(‘fist paragraph‘);
p.appendChild(t);
farg.appendChild(p);
p = document.creatElement(‘p‘);
t = document.creatTextNode(‘second paragraph‘);
p.appendChild(t);
farg.appendChild(p);
document.body.appendChild(frag); //相比前面的方法,这里仅仅引起一次回流,倘若页面里有很多这样的操作,利用文档随便将会提升很多
//BAD WAY
for(循环) {
el.style.left = el.offsetLeft + 5 + "px";
el.style.top = el.offsetTop + 5 + "px";
}
// 这样写好点
var left = el.offsetLeft,
top = el.offsetTop,
s = el.style;
for (循环) {
left += 10;
top += 10;
s.left = left + "px";
s.top = top + "px";
}
或者使用 translate 替代 top
查了下,好像translate会启动硬件加速
<div class="test"></div>
<style>
.test {
position: absolute;
top: 10px; //transform: translateY(50px);
width: 100px;
height: 100px;
background: red;
}
</style>
<script>
setTimeout(() => {
// 引起回流
document.querySelector(‘.test‘).style.top = ‘100px‘
}, 1000)
</script>
,因为前者只会引起重绘,后者会引发回流(改变了布局)
所以面试的时候可能问你要给一个dom元素循环添加一组dom元素,要放在循环内还是循环外:其实考的是回流和重绘
for (let i = 0; i < 1000; i++) {
// 获取 offsetTop 会导致回流,因为需要去获取正确的值
console.log(document.querySelector(‘.test‘).style.offsetTop)
}
比如对于video
标签,浏览器会自动将该节点变为图层。
标签:优化 使用 硬件 简单的 script 浏览器渲染 展示 aci 加载
原文地址:https://www.cnblogs.com/chaimi/p/10262994.html