`
fuhao200866
  • 浏览: 75096 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

减少浏览器重解析 JavaScript DOM操作优化方案

阅读更多

在我们开发互联网富应用(RIA)时,我们经常写一些JavaScript脚本来修改或者增加页面元素,这些工作最终是DOM——或者说文档对象模型——来完成的,而我们的实现方式会影响到应用的响应速度。

DOM操作会导致浏览器重解析(reflow),这是浏览器的一个决定页面元素如何展现的计算过程。直接修改DOM,修改元素的CSS样式,修改浏览器的窗口大小,都会触发重解析。读取元素的布局属性比如offsetHeithe或者offsetWidth也会触发重解析。重解析需要花费计算时间,因此重解析触发的越少,应用就会越快。

DOM操作通常要不就是修改已经存在的页面上的元素,要不就是创建新的页面元素。下面的4种优化方案覆盖了修改和创建DOM节点两种方式,帮助你减少触发浏览器重解析的次数。

方案一:通过CSS类名切换来修改DOM

这个方案让我们可以一次性修改一个元素和它的子元素的多个样式属性而只触发一次重解析。

需求

我们现在需要写一个函数来修改一个超链接的几个样式规则。要实现很简单,把这几个规则对应的属性逐一改了就好了。但是带来的问题是,每修改一个样式属性,都会导致一次页面的重解析。

  1. function selectAnchor(element) {  
  2.   element.style.fontWeight = 'bold';  
  3.   element.style.textDecoration = 'none';  
  4.   element.style.color = '#000';  

解决方案

要解决这个问题,我们可以先创建一个样式名,并且把要修改的样式规则都放到这个类名上,然后我们给超链接添加上这个新类名,就可以实现添加几个样式规则而只触发一次重解析了。这个模式还有个好处是也实现了表现和逻辑相分离。

  1. .selectedAnchor {  
  2.   font-weight: bold;  
  3.   text-decoration: none;  
  4.   color: #000;  
  5. }  
  6. function selectAnchor(element) {  
  7.   element.className = 'selectedAnchor';  

方案二:在非渲染区修改DOM

上一个方案解决的是修改一个超链接的问题,当一次需要对很多个超链接进行相同修改的时候,这个方案就可以大显身手了。

需求

需求是这样的,我们要写一个函数来修改一个指定元素的子元素中所有的超链接的样式名(className)属性。要实现很简单,我们可以通过遍历每个超链接并且修改它们的样式名来完成任务。但是带来的问题就是,每修改一个超链接都会导致一次重解析。

  1. function updateAllAnchors(element, anchorClass) {  
  2.   var anchors = element.getElementsByTagName('a');  
  3.   for (var i = 0length = anchors.length; i < length; i ++) {  
  4.      anchors.className = anchorClass;  
  5.   }  

解决方案

要解决这个问题,我们可以把被修改的指定元素从DOM里面移除,再修改所有的超链接,然后在把这个元素插入回到它原来的位置上。为了完成这个复杂的操作,我们可以先写一个可重用的函数,它不但移除了这个DOM节点,还返回了一个把元素插回到原来的位置的函数。

  1. /**  
  2. * Remove an element and provide a function that inserts it into its original position  
  3. * @param element {Element} The element to be temporarily removed  
  4. * @return {Function} A function that inserts the element into its original position  
  5. **/  
  6.  
  7. function removeToInsertLater(element) {  
  8.   var parentNode = element.parentNode;  
  9.   var nextSibling = element.nextSibling;  
  10.   parentNode.removeChild(element);  
  11.   return function() {  
  12.     if (nextSibling) {  
  13.        parentNode.insertBefore(element, nextSibling);  
  14.     } else {  
  15.    parentNode.appendChild(element);  
  16.     }  
  17.   };  

有了上面这个函数,现在我们就可以在一个不需要解析渲染的元素上面修改那些超链接了。这样只在移除和插入元素的时候各触发一次重解析。

  1. function updateAllAnchors(element, anchorClass) {  
  2.   var insertFunction = removeToInsertLater(element);  
  3.   var anchors = element.getElementsByTagName('a');  
  4.   for (var i = 0length = anchors.length; i < length; i ++) {  
  5.      anchors.className = anchorClass;  
  6.   }  
  7.     insertFunction();  

方案三:一次性的DOM元素生成

这个方案让我们创建一个元素的过程只触发一次重解析。在创建完元素以后,先进行所有需要的修改,最后才把它插入到DOM里面去就可以了

需求

需求是这样的,实现一个函数,往一个指定的父元素上插入一个超链接元素。这个函数要同时可以设置这个超链接的显示文字和样式类。我们可以这样做:创建元素,插入到DOM里面,然后设置相应的属性。这就要触发3次重解析。

  1. function addAnchor(parentElement, anchorText, anchorClass) {  
  2.   var element = document.createElement('a');  
  3.   parentElement.appendChild(element);  
  4.   element.innerHTML = anchorText;  
  5.   element.className = anchorClass;  

解决方案

很简单,我们只要把插入元素这个操作放到最后做,就可以只进行一次重解析了。

  1. var element = document.createElement('a');  
  2. element.innerHTML = anchorText;  
  3. element.className = anchorClass;  
  4. parentElement.appendChild(element);  

复制代码不过,要是我们想要插入很多个超链接到一个元素里面的话,那么这个做法还是有问题:每插入一个超链接还是要触发一次重解析。下一个方案可以解决这个问题。

方案四:通过文档片段对象(DocumentFragment)创建一组元素

这个方案允许我们创建并插入很多个元素而只触发一次重解析。要实现这点需要用到所谓的文档片段对象(DocumentFragment)。我们先在 DOM之外创建一个文档片段对象(这样它也就不需要解析和渲染),然后我们在文档片段对象中创建很多个元素,最后我们把这个文档片段对象中所有的元素一次性放到DOM里面去,只触发一次重解析。

需求

我们要写一个函数,往一个指定的元素上面增加10个超链接。如果我们简单的直接插入10个超链接到元素上面,就会触发10次重解析。

  1. function addAnchors(element) {  
  2. var anchor;  
  3. for (var i = 0; i < 10; i ++) {  
  4.     anchor = document.createElement('a');  
  5.     anchor.innerHTML = 'test';  
  6.     element.appendChild(anchor);  
  7.     }  

解决方案

要解决这个问题,我们要先创建一个文档片段对象,然后把每个新创建的超链接都插入到它里面去。当我们把文档片段对象用appendChild命令插入到指定的节点时,这个文档片段对象的所有子节点就一起被插入到指定的元素里面,而且只需要触发一次重解析。

  1. function addAnchors(element) {  
  2.   var anchor, fragment = document.createDocumentFragment();  
  3.   for (var i = 0; i < 10; i ++) {  
  4.     anchor = document.createElement('a');  
  5.     anchor.innerHTML = 'test';  
  6.     fragment.appendChild(anchor);  
  7.   }  
  8.   element.appendChild(fragment);  
分享到:
评论

相关推荐

    [JavaScript.DOM高级程序设计](加)桑贝斯.扫描版.part1.rar

     3.1 DOM不是JavaScript,它是文档   3.2 DOM的级别   3.2.1 DOM 0 级   3.2.2 DOM 1 级   3.2.3 DOM 2 级   3.2.4 DOM 3 级   3.2.5 哪个级别适合你   3.3 创建示例文档   3.3.1 创建DOM...

    探析浏览器执行JavaScript脚本加载与代码执行顺序

    并且在所有浏览器中的行为都是一致的,原因也不难理解:浏览器需要一个稳定的DOM结构,而JavaScript可能会修改DOM(改变DOM结构或修改某个DOM节点),如果在JavaScript执行的同时还继续进行页面的解析,那么整个解析...

    javascript学习基础笔记之DOM对象操作

    DOM文档对象模型是HTML和XML的应用程序接口(API),DOM将整个页面规划成由节点层次构成的文档。...由于DOM的使用上的简便,因此它成为了Web浏览器和javascript最喜欢的方法。document对象是BOM的对

    html-dom-parser:HTML到DOM解析器

    html-dom-parser 在服务器(Node.js)和客户端(浏览器)上均可使用HTML到DOM解析器: HTMLDOMParser(string[, options])解析器将HTML字符串转换为描述DOM树JavaScript对象。例子const parse = require ( '...

    [JavaScript.DOM高级程序设计](加)桑贝斯.扫描版.part3.rar

     3.1 DOM不是JavaScript,它是文档   3.2 DOM的级别   3.2.1 DOM 0 级   3.2.2 DOM 1 级   3.2.3 DOM 2 级   3.2.4 DOM 3 级   3.2.5 哪个级别适合你   3.3 创建示例文档   3.3.1 创建DOM...

    [JavaScript.DOM高级程序设计](加)桑贝斯.扫描版.part2.rar

     3.1 DOM不是JavaScript,它是文档   3.2 DOM的级别   3.2.1 DOM 0 级   3.2.2 DOM 1 级   3.2.3 DOM 2 级   3.2.4 DOM 3 级   3.2.5 哪个级别适合你   3.3 创建示例文档   3.3.1 创建DOM...

    JavaScript应用开发实践指南

    第2章介绍了如何在浏览器中运用JavaScript语言,初步提到适时运用CSS规则、提升用户体验的原则。第3章解析与DOM、数据存储、创建交互层等有关的术语。第4章介绍DOM的基本构成和操作。第5章讲解了JavaScript数据存储...

    dom-parser:使用正则表达式的dom解析器支持浏览器,节点,react-native等

    使用javascript正则表达式的dom解析器。 不需要节点环境或特殊的浏览器!!! 支持react,react-native,vue等... 安装 npm install --save react-native-dom-parser 用法 import DomSelector from 'react-native-...

    Node.js——基于Chrome JavaScript运行时建立的平台

    JS解析器只是JS代码运行的一种环境,浏览器是JS运行的一种环境,浏览器为JS提供了操作DOM对象和window对象等接口。Node.js也是JS的一种运行环境,node.js为JS提供操作文件、创建http服务、创建TCP、UDP服务等接口,...

    javascript先序遍历DOM树的方法

    DOM树由文档中的所有节点(元素节点、文本节点、注释节点等)所构成的一个树结构,DOM树的解析和构建是浏览器要实现的关键功能。既然DOM树是一个树结构,那么我们就可以使用遍历树结构的相关方法来对DOM树进行遍历,...

    渲染篇 3:对症下药——DOM 优化原理与基本实践(1).md

    前端性能优化实践# 知识体系与小册格局 ## 写给读者 提起性能优化,大家现在脑海里第一时间会映射出什么内容呢? 可能是类似[“雅虎军规”]...具体来说,DNS 解析花时间,能不能尽量减少解析次数

    JavaScript Window浏览器对象模型原理解析

    浏览器对象模型 (BOM) 使 JavaScript 有能力与浏览器”对话”。 浏览器对象模型 (BOM) 浏览器对象模型(Browser Object Model (BOM))尚无正式标准。 由于现代浏览器已经(几乎)实现了 JavaScript 交互性方面的...

    JavaScript王者归来part.1 总数2

     12.1.4 HTML结构和DOM对象的关系--用JavaScript通过DOM来操作HTML文档   12.2 DOM与浏览器实现   12.2.1 关于DOM HTML API   12.2.2 DOM的级别和特性   12.2.3 DOM的一致性   12.2.4 差异性--浏览器的...

    JavaScript之DOM_动力节点Java学院整理

    由于HTML文档被浏览器解析后就是一棵DOM树,要改变HTML的结构,就需要通过JavaScript来操作DOM。 始终记住DOM是一个树形结构。操作一个DOM节点实际上就是这么几个操作: 更新:更新该DOM节点的内容,相当于更新了该...

    JS中DOM元素的操作等基础知识笔记

    目录1. DOM的概念和作用2.节点树3.DOM选择器:(查询、创建、添加,修改,删除)4.DOM的基本操作①.... 浏览器会根据 DOM 模型,将结构化文档(比如 HTML和 XML)解析成一系列的节点,再由这些节点组成一个树状结

    JavaScript Template JST模板引擎

    3、采用简易的语言来描述大段的字串以及Dom/DHTML操作 4、可以很方便的解析XML文件格式的数据到指定模板。 采用该引擎,可以让它来完全处理View方面的事情,服务端Module直接输出Data就可以。让你的MVC模式连成一体...

    浅谈Javascript中的12种DOM节点类型

    DOM的作用是将网页转为一个javascript对象,从而可以使用javascript对网页进行各种操作(比如增删内容)。浏览器会根据DOM模型,将HTML文档解析成一系列的节点,再由这些节点组成一个树状结构。DOM的最小组成单位叫做...

    JavaScript提升机制Hoisting详解

    刚接触到JavaScript的时候,便知道JavaScript是按顺序执行的,是如浏览器的解析DOM树一样的流程,解析DOM结构的时候,如果遇到JS脚本或者外联脚本便会停止解析,继续下载脚本之后,执行脚本,然后再解析DOM。...

    高性能JavaScript 重排与重绘(2)

    先回顾下前一篇文章高性能JavaScript DOM编程,主要提了两点优化,一是尽量减少DOM的访问,而把运算放在ECMAScript这一端,二是尽量缓存局部变量,比如length等等,最后介绍了两个新的API querySelector()以及...

Global site tag (gtag.js) - Google Analytics