DOM访问优化

news/2024/7/19 15:23:50 标签: java, js, javascript, web, python

2010 update: Lo, the Web Performance Advent Calendar hath moved

2010年更新: Lo, Web Performance Advent Calendar已移动

Dec 18 This post is part of the 2009 performance advent calendar experiment. Stay tuned for the articles to come.

12月18日,该帖子是2009年效果降临日历实验的一部分。 请继续关注未来的文章。

This blog series has sailed from the shores of networking, passed down waterfalls and reflows, and arrived in ECMAScriptland. Now, turns out there's one bridge to cross to get to DOMlandia.

这个博客系列从网络的海岸航行,经过瀑布和回流,到达了ECMAScriptland。 现在,发现有一座桥梁可以横渡到DOMlandia。

(OK, I need to get some sleep, evidently. Anyway.) Ara Pehlivanian talked about strategies for loading JavaScript code. Yesterday's post was about rendering and how you can prevent making things worse in JavaScript. Today's post will be about DOM access optimizations and, if all is good, tomorrow's post will round up the JavaScript discussion with some techniques for extreme optimization.

(好吧,显然我需要睡觉。无论如何。) Ara Pehlivanian谈到了加载JavaScript代码的策略。 昨天的帖子是关于渲染以及如何防止JavaScript变得更糟的。 今天的帖子将讨论DOM访问优化,如果一切顺利,明天的帖子将使用一些极限优化技术来完善JavaScript讨论。

DOM是什么 (What's with the DOM)

Document Object Model (DOM) is a language-independent API for accessing and working with a document. Could be an HTML document, or XML, SVG and so on. DOM is not ECMAScript. ECMAScript is just one way to work with the DOM API. They both started in the web browser but now things are different. ECMAscript has many other uses and so has the DOM. You can generate a page server side, using the DOM is you like. Or script Photoshop with ECMAScript.

文档对象模型(DOM)是一种独立于语言的API,用于访问和使用文档。 可以是HTML文档,也可以是XML,SVG等。 DOM不是ECMAScript。 ECMAScript只是使用DOM API的一种方式。 他们都是从网络浏览器开始的,但现在情况有所不同。 ECMAscript有许多其他用途,DOM也有。 您可以使用DOM来生成页面服务器端。 或使用ECMAScript编写Photoshop脚本。

All that goes to show that ECMAScript and DOM are now separate, they make sense on their own, they don't need each other. And they are kept separate by the browsers.

所有这些表明,ECMAScript和DOM现在是分开的,它们自己有意义,彼此不需要。 并且它们由浏览器保持分开。

For example WebCore is the layout, rendering and DOM library used by WebKit, while JavaScriptCore (most recently rewritten as SquirrelFish) is the implementation of ECMAScript. In IE - Trident (DOM) and JScript. In Firefox - Gecko (DOM) and SpiderMonkey (ECMAScript).

例如,WebCore是WebKit使用的布局,渲染和DOM库,而JavaScriptCore(最近重写为SquirrelFish)是ECMAScript的实现。 在IE中-Trident(DOM)和JScript。 在Firefox中-Gecko(DOM)和SpiderMonkey(ECMAScript)。

收费桥 (The toll bridge)

An excellent analogy I heard in this video from John Hrvatin of MSIE is that we can think of the DOM as a piece of land and JavaScript/ECMAScript as another piece of land. Both connected via a toll bridge. I tried to illustrate this analogy here.

我从MSIE的John Hrvatin的这段视频中听到的一个很好的类比是,我们可以将DOM视为一块土地,而将JavaScript / ECMAScript视为另一块土地。 两者均通过收费桥连接。 我试图在这里说明这种类比。

domland and ecmaland connected with a bridge

All your JavaScript code that doesn't require a page - code such as loops, ifs, variables and a handful of built-in functions and objects - lives in ECMALand. Anything that starts with document.* lives in DOMLand. When your JavaScript needs to access the DOM, you need to cross that bridge to DOMlandia. And the bad part is that it's a toll bridge and you have to pay a fee every time you cross. So, the more you cross that bridge, the more you pay your performance toll.

您不需要页面的所有JavaScript代码-诸如循环,if,变量和少数内置函数和对象之类的代码-都位于ECMALand中。 任何以document.*开头的document.*存在于DOMLand中。 当您JavaScript需要访问DOM时,您需要跨过DOMlandia。 不利的是,这是一个收费站,您每次穿越时都必须付费。 因此,越过这座桥,您付出的绩效费用就越多。

多么糟糕? (How bad?)

So, how serious is that performance penalty? Pretty serious actually. DOM access and manipulations is probably the most expensive activity you do in your JavaScript, followed by layouting (reflowing and painting activities). When you look for problems in your JavaScript (you use a profile instead of shooting in the dark, of course, but still) most likely it's the DOM that's slowing you down.

那么,这种性能损失有多严重? 真的很认真。 DOM访问和操作可能是您在JavaScript中进行的最昂贵的活动,其次是布局(重排和绘画活动)。 当您在JavaScript中寻找问题时(当然,您可以使用配置文件而不是在黑暗中拍摄),但很可能是DOM拖慢了您的速度。

As an illustration, consider this bad, bad code:

作为说明,请考虑以下错误代码:

// bad
for (var count = 0; count < 15000; count++) {  
    document.getElementById('here').innerHTML += 'a';  
}

This code is bad because it touches the DOM twice on every loop tick. It doesn't cache the reference to the DOM element, it looks for that element every time. Then this code also updates the live DOM which means it causes a reflow and a repaint (which are probably buffered by the browsers and executed in batches, but still bad).

该代码很糟糕,因为它在每个循环滴答中都两次触摸DOM。 它不会缓存对DOM元素的引用,而是每次都会查找该元素。 然后,此代码还将更新实时DOM,这意味着它将导致重排和重绘(可能由浏览器缓冲并分批执行,但仍然很糟糕)。

Compare with the following code:

与以下代码进行比较:

// better
var content = '';
for (var count = 0; count < 15000; count++) {  
    content += 'a';  
}
document.getElementById('here').innerHTML += content;

Here's we only touch the DOM twice at the end. The whole time otherwise we work in ECMAland with a local variable.

这是我们最后只触摸DOM两次的情况。 否则,我们会一直使用带有局部变量的ECMAland工作。

And how bad is the bad example? It's over 100 times worse in IE6,7 and Safari, over 200 times worse in FF3.5 and IE8 and about 50 times worse in Chrome. We're not talking percentages here - we talk 100 times worse.

坏榜样有多糟? 在IE6,7和Safari中,性能下降了100倍以上;在FF3.5和IE8中,性能下降了200倍以上;在Chrome中,性能下降了约50倍。 我们这里不是在说百分比-我们说的差了100

Now obviously this is a bad and made up example, but it does show the magnitude of the problem with DOM access.

现在显然这是一个不好的例子,但是确实显示了DOM访问问题的严重性。

缓解问题-请勿触摸DOM (Mitigating the problem - don't touch the DOM)

How to speed up DOM access? Simply do less of it. If you have a lot of work to do with the DOM, cache references to DOM elements so you don't have to query the DOM tree every time to find them. Cache the values of the DOM properties if you'll do a chunk of of work with them. And by cache I mean simply assign them to local variables. Use selectors API where available instead of crawling the DOM yourself (upgrade your JavaScript library if it's not taking advantage of the selectors API). Be careful with HTML Collections.

如何加快DOM访问? 简单地少做些。 如果您有很多与DOM相关的工作,请缓存对DOM元素的引用,这样就不必每次都查询DOM树来查找它们。 如果您要对DOM属性的值进行大量工作,则对它们进行缓存。 通过缓存,我的意思是简单地将它们分配给局部变量。 使用可用的选择器API而不是自己爬网DOM(如果未利用选择器API,请升级JavaScript库)。 注意HTML集合。

// bad
document.getElementById('my').style.top = "10px";
document.getElementById('my').style.left = "10px";
document.getElementById('my').style.color = "#dad";
 
// better
var mysty = document.getElementById('my').style;
mysty.top = "10px";
mysty.left = "20px";
mysty.color = "#dad";
 
// better
var csstext = "; top: 10px; left: 10px; color: #dad;";
document.getElementById('my').style.cssText += csstext

Basically, every time you find you're accessing some property or object repeatedly, assign it to a local variable and work with that local variable.

基本上,每次您发现要重复访问某些属性或对象时,请将其分配给局部变量并使用该局部变量。

HTMLCollections (HTMLCollections)

HTMLCollections are objects returned by calls to document.getElementsByTagName(), document.getElementsByClassName() and others, also by accessing the old-style collections document.links, document.images and the like. These HTMLCollection objects are array-like, list-like objects that contain pointers to DOM elements.

HTMLCollections是通过调用document.getElementsByTagName()document.getElementsByClassName()等返回的对象,也可以通过访问旧式集合document.linksdocument.images等返回。 这些HTMLCollection对象是类似于数组的,类似于列表的对象,其中包含指向DOM元素的指针。

The special thing about them is that they are live queries against the underlying document. And they get re-run a lot, for example when you loop though the collection and access its length. The fact that you touch the length requires re-querying of the document so that the most up-to-date information is returned to you.

关于它们的特殊之处在于它们是针对基础文档的实时查询。 而且它们会重新运行很多,例如,当您遍历集合并访问其length 。 您触摸length的事实要求重新查询文档,以便将最新信息返回给您。

Here's an example:

这是一个例子:

// slow
var coll = document.getElementsByTagName('div'); 
for (var count = 0; count < coll.length; count++) { 
    /* do stuff */ 
}
 
// faster
var coll = document.getElementsByTagName('div'),
    len = coll.length; 
for (var count = 0; count < len; count++) { 
    /* do stuff */ 
}

The slower version requeries the document, the faster doesn't because we use the local value for the length. How slower is the slower? Depends on the document and how many divs in it, but in my tests anywhere between 2 times slower (Safari) to 200 times slower (IE7)

版本越慢,重新查询文档的速度就越快,这不是因为我们使用本地值作为长度。 慢多少慢? 取决于文档及其中的div数量,但在我的测试中,速度要慢2倍(Safari)到200倍(IE7)

Another thing you can do (especially if you'll loop the collection a few times) is to copy the collection into an array beforehand. Accessing the array elements will be significantly faster than accessing the DOM elements in the collection, again 2 to 200 times faster.

您可以做的另一件事(尤其是如果您要循环几次该集合)是事先将集合复制到数组中。 访问数组元素将比访问集合中的DOM元素快得多,再次快2到200倍。

Here's an example function that turns the collection into an array:

这是一个将集合变成数组的示例函数:

function toArray(coll) {
    for (var i = 0, a = [], len = coll.length; i < len; i++) {
        a[i] = coll[i];
    }
    return a;
}

If you do that you also need to account for the one-off cost of copying that collection to an array.

如果这样做,还需要考虑将该集合复制到阵列的一次性费用。

使用事件委托 (Using event delegation)

Event delegation is when you attach event listener to a parent element and it handles all the events for the children because of the so-called event bubbling It's a graceful way to relieve the browser from a lot of extra work. The benefits:

事件委托是指将事件侦听器附加到父元素时,由于所谓的事件冒泡,它为子代处理所有事件。这是一种减轻浏览器工作量的优雅方法。 好处:

  • You need to write less event-attaching code.

    您需要编写更少的事件附加代码。
  • You will usually use fewer functions to handle the events because you're attaching one function to handle parent events, not individual function for each child element. This means less functions to store in memory and keep track of.

    通常,您将使用较少的函数来处理事件,因为要附加一个函数来处理父事件,而不是为每个子元素添加单个函数。 这意味着更少的功能可以存储在内存中并进行跟踪。
  • Less events the browser needs to monitor

    浏览器需要监视的事件更少
  • Easier to detach event handlers when an element is removed and therefore easier to prevenk IE memory leaks. Sometimes you don't even need to detach the event handler if children change, but the event-handling parent stays the same.

    删除元素时,更容易分离事件处理程序,因此更容易防止IE内存泄漏。 有时,如果子项发生更改,甚至不需要分离事件处理程序,但是事件处理父级保持不变。

谢谢阅读! (Thanks for reading!)

  • Don't touch the DOM when you can avoid it, cache DOM access to local references

    当可以避免使用DOM时,不要触摸它,而是缓存DOM对本地引用的访问
  • Cache length of HTMLCollections to a local variable while looping (good practice for any collections or arrays looping anyway). Copy the collection to an array if you'll be looping several times.

    循环时将HTMLCollections的长度缓存到局部变量中(对于任何循环的集合或数组而言,都是好的做法)。 如果要循环几次,请将集合复制到数组中。
  • Use event delegation

    使用事件委托

链接(Links)

  • Efficient JavaScript - Nicholas Zakas's presentation at Velocity conf

    高效JavaScript -Nicholas Zakas在Velocity conf上的演讲

  • Efficient JavaScript - dev.Opera

    高效JavaScript -dev.Opera

  • Event delegation how-tos

    活动委派方式-TOS

Tell your friends about this post on Facebook and Twitter

在Facebook和Twitter上告诉您的朋友有关此帖子的信息

翻译自: https://www.phpied.com/dom-access-optimization/


http://www.niftyadmin.cn/n/1306055.html

相关文章

小球自由落体_自由落体瀑布

小球自由落体2010 update: Lo, the Web Performance Advent Calendar hath moved 2010年更新&#xff1a; Lo&#xff0c; Web Performance Advent Calendar已移动 Dec 14 This post is part of the 2009 performance advent calendar experiment. Stay tuned for the articles…

JSON字符串转换为JSON对象

JSON字符串转换为JSON对象 1、eval() 2、.parseJSON() 3、JSON.parse()

YUI CSS Min –第2部分

The first part is here. It was more about building the YUICompressor, writing and running test cases. Now lets see what the compressor does exactly to your CSS. 第一部分在这里。 它更多地是关于构建YUICompressor&#xff0c;编写和运行测试用例。 现在&#xff0…

iphone 微信缓存_iPhone缓存

iphone 微信缓存2010 update: Lo, the Web Performance Advent Calendar hath moved 2010年更新&#xff1a; Lo&#xff0c; Web Performance Advent Calendar已移动 Dec 22 This post is part of the 2009 performance advent calendar experiment. Stay tuned for the artic…

JSON对象转换为JSON字符串

JSON对象转换为JSON字符串 1、.toJSONString() 2、JSON.stringify()

TypeError:Error #1009

1、错误描述 TypeError:Error #1009&#xff1a;无法访问空对象引用的属性和方法 2、错误原因 3、解决办法

硅谷(我去过的最崎place的地方)

Excuse me, my dearest reader for subjecting you to this (*cough vogon poetry*). My only excuse is its Friday. 对不起&#xff0c;我最亲爱的读者使您受到了这一影响(*咳嗽vogon诗歌*)。 我唯一的借口是星期五。 So here comes another one of those. This time a cove…

HTML5可以省略全部标记的元素

HTML5可以省略全部标记的元素 1、body 2、colgroup 3、html 4、head 5、tbody