欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > asp.net >内容正文

asp.net

asp.net ajax 怎么获取前端ul li_字节前端提前批面试题:触发了几次回流几次重绘...

发布时间:2025/3/20 asp.net 39 豆豆
生活随笔 收集整理的这篇文章主要介绍了 asp.net ajax 怎么获取前端ul li_字节前端提前批面试题:触发了几次回流几次重绘... 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

一道字节面试题刷新了我的认知,又学到了新知识,开心。

刚开始我说了答案是各3次,因为获取一次offsetWidth一次,然后改变样式一次。

但是后来发现之所以offsetWidth会触发重排是因为刷新渲染队列。而在这道题中,之前的渲染队列为空,所以不会触发重排。所以两次。

后面发现又错了,是因为有渲染队列,所以因该是一次。不懂渲染队列没关系,往下看,就懂了。

当然要分为古董浏览器和现代浏览器。现代浏览器(也就是说有渲染队列的)应当是一次,古董的应当是2次

一.什么是重绘与重排

浏览器下载完页面中的所有组件——HTML标记、JavaScript、CSS、图片之后会解析生成两个内部数据结构——DOM树和渲染树。

DOM树表示页面结构,渲染树表示DOM节点如何显示。DOM树中的每一个需要显示的节点在渲染树种至少存在一个对应的节点(隐藏的DOM元素disply值为none 在渲染树中没有对应的节点)。渲染树中的节点被称为“帧”或“盒”,符合CSS模型的定义,理解页面元素为一个具有填充,边距,边框和位置的盒子。一旦DOM和渲染树构建完成,浏览器就开始显示(绘制)页面元素。

当DOM的变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。完成重排后,浏览器会重新绘制受影响的部分到屏幕,该过程称为重绘。由于浏览器的流布局,对渲染树的计算通常只需要遍历一次就可以完成。但table及其内部元素除外,它可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。这也是为什么我们要避免使用table做布局的一个原因。

并不是所有的DOM变化都会影响几何属性,比如改变一个元素的背景色并不会影响元素的宽和高,这种情况下只会发生重绘。

不管页面发生了重绘还是重排,它们都会影响性能

二.怎样触发重排

页面布局和元素几何属性的改变就会导致重排 下列情况会发生重排

  • 页面初始渲染
  • 添加/删除可见DOM元素
  • 改变元素位置
  • 改变元素尺寸(宽、高、内外边距、边框等)
  • 改变元素内容(文本或图片等)
  • 改变窗口尺寸

不同的条件下发生重排的范围及程度会不同

某些情况甚至会重排整个页面,比如滑动滚动条

三.浏览器优化

例如:

假如我要用js修改某个div的样式

div.style.left = '10px'; div.style.top = '10px'; div.style.width = '10px'; div.style.height = '10px';

我们修改了元素的left、top、width、height属性 ,满足我们发生重排的条件 ,理论上会发生4次重排 ,但是实际上只会发生1次重排 ,因为我们现代的浏览器都有渲染队列的机制 ,当我改变了元素的一个样式会导致浏览器发生重排或重绘时 ,它会进入一个渲染队列 ,然后浏览器继续往下看,如果下面还有样式修改 ,那么同样入队 ,直到下面没有样式修改 ,浏览器会按照渲染队列批量执行来优化重排过程,一并修改样式 ,这样就把本该4次的重排优化为1次

But,当我们写如下代码时:

div.style.left = '10px'; console.log(div.offsetLeft);div.style.top = '10px'; console.log(div.offsetTop);div.style.width = '20px'; console.log(div.offsetWidth);div.style.height = '20px'; console.log(div.offsetHeight);

还是1次重排吗?

Obviously not! 此时发生了4次重排!

上文不是说浏览器有渲染队列优化机制吗? 为什么会有4次?

这和offsetLeft/Top/Width/Height有关

offsetTop、offsetLeft、offsetWidth、offsetHeight clientTop、clientLeft、clientWidth、clientHeight scrollTop、scrollLeft、scrollWidth、scrollHeight getComputedStyle()(IE中currentStyle)

这些会强制刷新队列要求样式修改任务立刻执行

因为浏览器并不确定在下面的代码中是否还有修改同样的样式,为了获取到当前正确的的即时值不得不立刻执行渲染队列触发重排!!!

四.重绘与重排性能优化

1.分离读写操作

我们就可以对上面的代码进行优化

div.style.left = '10px'; div.style.top = '10px'; div.style.width = '20px'; div.style.height = '20px';console.log(div.offsetLeft); console.log(div.offsetTop); console.log(div.offsetWidth); console.log(div.offsetHeight);

这样就仅仅发生1次重排了!

2.样式集中改变

还是我们最初修改样式的代码

div.style.left = '10px'; div.style.top = '10px'; div.style.width = '20px'; div.style.height = '20px';

虽然现代浏览器有渲染队列的优化机制,但是古董浏览器效率仍然底下,触发了4次重排 ,即便这样,我们仍然可以做出优化 ,我们需要cssText属性合并所有样式改变

div.style.cssText = 'left:10px;top:10px;width:20px;height:20px;';

这样只需要修改DOM一次一并处理,仅仅触发了1次重排 ,而且只用了一行代码

除了cssText以外,我们还可以通过修改class类名来进行样式修改

div.className = 'new-class';

这种办法可维护性好,还可以帮助我们免除显示性代码,但是会消耗一点点的性能

3.缓存布局信息

div.style.left = div.offsetLeft + 1 + 'px'; div.style.top = div.offsetTop + 1 + 'px';

这种读操作完就执行写操作造成了2次重排

缓存可以进行优化

var curLeft = div.offsetLeft; var curTop = div.offsetTop; div.style.left = curLeft + 1 + 'px'; div.style.top = curTop + 1 + 'px';

相当于是分离读写操作,优化为1次重排

4.元素批量操作

现在我们想要向ul中循环添加大量li (如果ul还不存在,最好的办法是先循环添加li到ul,然后再把ul添加到文档,1次重排)

var ul = document.getElementById('demo'); for(var i = 0; i < 1e5; i++){var li = document.createElement('li');var text = document.createTextNode(i);li.appendChild(text);ul.appendChild(li); }

我可以做出下面的优化

var ul = document.getElementById('demo'); ul.style.display = 'none'; for(var i = 0; i < 1e5; i++){var li = document.createElement('li');var text = document.createTextNode(i);li.appendChild(text);ul.appendChild(li); } ul.style.display = 'block'; var ul = document.getElementById('demo'); var frg = document.createDocumentFragment(); for(var i = 0; i < 1e5; i++){var li = document.createElement('li');var text = document.createTextNode(i);li.appendChild(text);frg.appendChild(li); }ul.appendChild(frg); var ul = document.getElementById('demo'); var clone = ul.cloneNode(true); for(var i = 0; i < 1e5; i++){var li = document.createElement('li');var text = document.createTextNode(i);li.appendChild(text);clone.appendChild(li); } ul.parentNode.replaceChild(clone,ul);

上面的方法减少重绘和重排的原理很简单

  • 元素脱离文档
  • 改变样式
  • 元素回归文档

而改变元素就分别使用了隐藏元素、文档碎片和克隆元素

总结

以上是生活随笔为你收集整理的asp.net ajax 怎么获取前端ul li_字节前端提前批面试题:触发了几次回流几次重绘...的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。