DOM操作为什么慢?

DOM对象其实也是一个内存对象,为什么对DOM的操作这么慢?
其实是因为DOM操作会引起浏览器的render和paint操作,
而这两个操作比较耗时,所以造成对DOM操作比较慢。
关于render和paint的概念需要理解一下浏览器呈现一
个页面需要哪些操作。

浏览器如何呈现一个页面

浏览器如何呈现一个页面
一个完整的页面包含html和css以及js,从浏览器加载完这些资源文件到呈现一个完整的页面需要经过很多的步骤。
- 首先html解析器会解析html,生成一个DOM树,css解析器解析css文件同样生成一个属性结构的数据。
- dom tree和css rule tree生成render tree,render tree中的节点不仅仅包含了节点的内容,还包括节点的样式属性
- 浏览器对dom tree进行layout计算,这一步进行的操作是计算布局信息,包括各个节点的位置以及大小。
- 根据前面的结果进行页面的绘制。

哪些操作会引起浏览器的render和paint呢?

前面说到过,对DOM操作的慢是因为操作DOM的时候会引起浏览器的
render和paint,那么哪些操作会引起这些render和paint的行为呢?

  • 通过js获取需要计算的DOM属性
  • 添加删除DOM元素
  • resize浏览器窗口大小
  • css伪类的激活
  • 改变字体
  • 通过js修改DOM元素的样式并涉及到尺寸的改变

如何减少render和paint

  • 离线操作DOM
    当需要大量的操作DOM元素的时候,为了避免浏览器多次layout和paint,可以cloneNode,将DOM操作变成纯粹的内存操作
    操作完成之后替换原来的DOM元素。如果是添加多个节点,将所有DOM节点都在内存中拼装完成之后再append到DOM中。

  • 隐藏之后再操作
    对隐藏DOM元素进行操作是不会触发浏览器的layout和repaint的,其实display:none的元素根本就不会出现在render tree中,操作完成之后
    再将其显示在页面上。

设置某些css样式也会造成页面的reflow和repaint, css样式对于浏览器render的影响

### 浏览器画图性能低下的原因 浏览器中的画图功能主要依赖于 HTML5 提供的 Canvas API 和 SVG 技术。然而,在实际应用中,可能会遇到性能瓶颈。以下是导致浏览器画图性能低下的几个主要原因: #### 1. 屏幕重绘频率过高 对于图形用户界面的应用而言,性能问题的主要原因之一在于屏幕重绘效率低下[^3]。当用户调整窗口大小或滚动页面时,会触发大量的重绘事件。如果这些事件处理不当,可能超过程序能够响应的速度,从而引发卡顿。 #### 2. 不同浏览器间的实现差异 不同的浏览器对 Canvas 的支持和优化程度存在显著差异[^1]。某些浏览器可能在特定硬件上表现更优,而其他浏览器则可能出现明显的性能下降。这种不一致性使得开发者难以预测其应用程序的表现。 #### 3. 滚动事件监听带来的开销 前端开发中最常见的性能问题之一是在滚动事件上的过度计算[^4]。当绑定滚动事件并执行复杂的逻辑时,由于该事件被频繁触发,可能导致 JavaScript 执行线程与 DOM 渲染线程之间的相互阻塞现象。 --- ### 性能优化的方法 为了提升浏览器画图的性能,可以从以下几个方面入手: #### 减少不必要的重绘操作 通过忽略那些“迟到”的重绘请求来降低 CPU 负载。例如,可以采用防抖 (debounce) 或节流 (throttle) 方法减少重复调用次数,避免因高频次的操作引起资源浪费。 ```javascript function throttle(func, limit) { let lastFunc; let lastRan; return function() { const context = this; const args = arguments; if (!lastRan) { func.apply(context, args); lastRan = Date.now(); } else { clearTimeout(lastFunc); lastFunc = setTimeout(function() { if ((Date.now() - lastRan) >= limit) { func.apply(context, args); lastRan = Date.now(); } }, limit - (Date.now() - lastRan)); } }; } ``` #### 利用离屏缓冲区绘制复杂图像 创建一个隐藏的 `<canvas>` 元素作为临时工作区域完成所有的预渲染任务后再将其复制回可见 canvas 上显示出来。这种方法减少了每次重新构建整个场景所需的时间消耗。 ```html <canvas id="mainCanvas"></canvas> <script> const offscreenCanvas = document.createElement('canvas'); offscreenCanvas.width = mainCanvas.width; offscreenCanvas.height = mainCanvas.height; // Perform complex drawing on the off-screen buffer first. const ctxOffScreen = offscreenCanvas.getContext('2d'); ctxOffScreen.fillStyle = 'blue'; ctxOffScreen.fillRect(0, 0, offscreenCanvas.width / 2, offscreenCanvas.height); // Then transfer it to visible canvas once done. const ctxMain = mainCanvas.getContext('2d'); ctxMain.drawImage(offscreenCanvas, 0, 0); </script> ``` #### 避免跨浏览器兼容性陷阱 考虑到各主流厂商间存在的细微差别,建议定期测试目标平台最新版本下各自特性支持状况,并适时利用 polyfill 解决缺失的功能点。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值