你对加速Javascript DOM操作优化的方法是否熟悉,在我们开发互联网富应用(RIA)时,我们经常写一些javascript脚本来修改或者增加页面元素,这些工作最终是DOM——或者说文档对象模型——来完成的,而我们的实现方式会影响到应用的响应速度。
加速Javascript DOM操作优化
在我们开发互联网富应用(RIA)时,我们经常写一些javascript脚本来修改或者增加页面元素,这些工作最终是DOM——或者说文档对象模型——来完成的,而我们的实现方式会影响到应用的响应速度。
Javascript DOM操作会导致浏览器重解析(reflow),这是浏览器的一个决定页面元素如何展现的计算过程。直接修改DOM,修改元素的CSS样式,修改浏览器的窗口大小,都会触发重解析。读取元素的布局属性比如offsetHeithe或者offsetWidth也会触发重解析。重解析需要花费计算时间,因此重解析触发的越少,应用就会越快。
Javascript DOM操作通常要不就是修改已经存在的页面上的元素,要不就是创建新的页面元素。下面有两种优化方案,大致覆盖了修改和创建DOM节点两种方式,帮助你减少触发浏览器重解析的次数。
方案一:通过CSS类名切换来修改DOM
这个方案让我们可以一次性修改一个元素和它的子元素的多个样式属性而只触发一次重解析。
需求:
(emu注:原文作者写到这里的时候脑子显然短路了一下,把后面的Out-of-the-flowDOMManipulation模式要解决的问题给摆到这里来了,不过从示范代码中很容易明白作者真正想描述的问题,因此emu就不照翻原文了)
我们现在需要写一个函数来修改一个超链接的几个样式规则。要实现很简单,把这几个规则对应的属性逐一改了就好了。但是带来的问题是,每修改一个样式属性,都会导致一次页面的重解析。
- functionselectAnchor(element){
- element.style.fontWeight='bold';
- element.style.textDecoration='none';
- element.style.color='#000';
- }
解决方案:
要解决这个问题,我们可以先创建一个样式名,并且把要修改的样式规则都放到这个类名上,然后我们给超链接添加上这个新类名,就可以实现添加几个样式规则而只触发一次重解析了。这个模式还有个好处是也实现了表现和逻辑相分离。
- .selectedAnchor{
- font-weight:bold;
- text-decoration:none;
- color:#000;
- }
- functionselectAnchor(element){
- element.className='selectedAnchor';
- }
介绍了加速Javascript DOM操作优化的方案一,下面来看一下方案二。#p#
方案二:在非渲染区修改DOM
(emu注:作者在这里再次脑子短路,把DocumentFragmentDOMGeneration模式的介绍提前到这里来了,emu只好再次发挥一下)
上一个方案解决的是修改一个超链接的问题,当一次需要对很多个超链接进行相同修改的时候,这个方案就可以大显身手了。
需求:
需求是这样的,我们要写一个函数来修改一个指定元素的子元素中所有的超链接的样式名(className)属性。要实现很简单,我们可以通过遍历每个超链接并且修改它们的样式名来完成任务。但是带来的问题就是,每修改一个超链接都会导致一次重解析。
- functionupdateAllAnchors(element,anchorClass){
- varanchors=element.getElementsByTagName('a');
- for(vari=0,length=anchors.length;i<length;i++){
- anchors[i].className=anchorClass;
- }
- }
解决方案:
要解决这个问题,我们可以把被修改的指定元素从DOM里面移除,再修改所有的超链接,然后在把这个元素插入回到它原来的位置上。为了完成这个复杂的操作,我们可以先写一个可重用的函数,它不但移除了这个DOM节点,还返回了一个把元素插回到原来的位置的函数。
- /**
- *Removeanelementandprovideafunction
- thatinsertsitintoitsoriginalposition
- *@paramelement{Element}Theelementtobetemporarilyremoved
- *@return{Function}Afunctionthatinsertstheelementintoitsoriginalposition
- **/
- functionremoveToInsertLater(element){
- varparentNode=element.parentNode;
- varnextSibling=element.nextSibling;
- parentNode.removeChild(element);
- returnfunction(){
- if(nextSibling){
- parentNode.insertBefore(element,nextSibling);
- }else{
- parentNode.appendChild(element);
- }
- };
- }
有了上面这个函数,现在我们就可以在一个不需要解析渲染的元素上面修改那些超链接了。这样只在移除和插入元素的时候各触发一次重解析。
- functionupdateAllAnchors(element,anchorClass){
- varinsertFunction=removeToInsertLater(element);
- varanchors=element.getElementsByTagName('a');
- for(vari=0,length=anchors.length;i<length;i++){
- anchors[i].className=anchorClass;
- }
- insertFunction();
- }
【编辑推荐】
- 揭露JavaScript DOM操作基本原则
- 减少浏览器重解析 JavaScript DOM操作优化方案
- JavaScript获取HTML DOM节点元素详解
- JavaScript和DOM轻松实现数据访问
- HTML DOM与XML DOM的区别与联系探究