Why is checking an attribute using dot notation before deleting faster than deleting the attribute directly?

I asked this question , and it turned out that when deleting an attribute from an element, checking whether the element first exists with elem.xxx!==undefined speeds up execution. Proof .

Why is it faster? . You need to go through the code more, and you will have to deal with the removeAttribute() method, depending on how you do it.

+8
performance javascript dom syntax conditional
source share
4 answers

Well, first of all, you need to know that elem.xxx does not match elem.getAttribute() or any other method regarding the attribute.

elem.xxx is a property of the DOM element, while the attribute and element in the HTML inside the DOM are both similar but different. For example, take this DOM element: <a href="#"> and this code:

 //Let say var a is the <a> tag a.getAttribute('href');// == # a.href;// == http://www.something.com/# (ie the complet URL) 

But take a custom attribute: <a custom="test">

 //Let say var a is the <a> tag a.getAttribute('custom');// == test a.custom;// == undefined 

Thus, you cannot compare speed, since they do not achieve the same result. But one of them is clearly faster, because the properties are quick access data, and the attribute uses the get / hasAttribute DOM functions.

Now, why without a condition is faster? Just because removeAttribute doesn't matter, the attribute is missing, it checks to see if it is.

Thus, using hasAttribute before removeAttribute seems to do the check twice, but the condition is a bit slower because you need to check if the condition for running the code is met.

+5
source share

I have a suspicion that the trees are the reason for the speed increase.

Trace trees were first introduced by Andreas Gal and Michael Franz of the University of California, Irvine in their article Incremental Generation of Dynamic Code with Trace Trees .

In his blog Tracing the Internet, Andreas Gal (co-author of the article) explains how Just-in-Time compilers work.

To explain the tracing of JIT compilers as boldly as possible (since my knowledge of the subject is not deep), the tracing JIT compiler does the following:

  • Initially, all the code that needs to be run is interpreted.
  • The count is executed for the number of times that each code path is executed (for example, the number of times that the true branch of the if executes).
  • When the number of code attempts is greater than the predefined threshold, the code path is compiled into machine code to speed up execution (for example, I believe that SpiderMonkey executes code paths executed more than once).

Now let's look at your code and understand what causes the speedup:

Test case 1: check

 if (elem.hasAttribute("xxx")) { elem.removeAttribute("xxx"); } 

This code has a code path (i.e., an if ). Remember that JIT tracking only optimizes code paths, not entire functions. This is what I believe is happening:

  • Since the code is validated by JSPerf, it is executed more than once (understatement). Therefore, it is compiled into machine code.
  • However, it still bears the overhead of an extra call to the hasAttribute function, which is not compiled by JIT, because it is not part of the conditional code (the code between curly braces).
  • Therefore, although the code inside curly braces is fast, the conditional check itself is slow because it is not compiled. This is interpreted. As a result, the code is slow.

Test case 2: Delete

 elem.removeAttribute("xxx"); 

In this test case, we have no conditional code codes. Therefore, the JIT compiler never starts. So the code is slow.

Test case 3: verification (point designation)

 if (elem.xxx !== undefined) { elem.removeAttribute("xxx"); } 

This is the same as the first test case with one significant difference:

  • A conditional check is a simple check for nonequivalence. Consequently, it does not carry the full overhead of a function call.
  • Most JavaScript interpreters optimize simple equivalence checks, for example, assuming a fixed data type for both variables. Since the data type elem.xxx or undefined does not change every iteration, this optimization makes conditional checking even faster.
  • The result is that conditional validation (albeit interpreted) does not slow down the compiled code process. Therefore, this code is the fastest.

Of course, this is just speculation on my part. I do not know the internal components of the JavaScript engine, and therefore my answer is not canonical. However, I think this is a good educated guess.

+2
source share

Your proof is wrong ...

elem.class !== undefined always evaluated as false , and therefore elem.removeAttribute("class") never called, so this test will always be faster.

The correct property in elem to use is className , for example:

 typeof elem.className !== "undefined" 
0
source share

As Carl-Andre Gagnon noted, accessing your own JavaScript resource and calling the DOM function / property are two different operations.

Some DOM properties are displayed as JavaScript properties using the DOM IDL ; this is not the same as JS special properties and requires DOM access. In addition, although DOM properties are displayed, there is no strict relationship with DOM attributes!

For example, inputElm.value = "x" will not update the DOM attribute, even if the element displays and reports the updated value. If the goal is to use DOM attributes, the only right method is to use hasAttribute/setAttribute , etc.


I am working on getting an “honest” micro-test for various function calls, but it is quite complicated, and many different optimizations are happening. Here is my best result , which I will use to argue my case.

Note that there is no if or removeAttribute to confuse the results, and I focus only on accessing the DOM / JS properties. In addition, I am trying to exclude the statement that the difference in speed is simply due to a function call, and I assign results to avoid glaring browser optimizations. YMMV.

remarks:

  • Access to the JS resource is fast. This is to be expected 1.2

  • A function call can result in a higher cost than direct access to properties 1 but not as slow as DOM properties or DOM functions. That is, it is not just a “function call” that makes hasAttribute much slower.

  • Access to DOM properties is slower than native access to JS properties; however, performance is very different between DOM properties and browsers. My updated micro-test shows a tendency that DOM access - whether through the DOM property or the DOM function - may be slower than native access to JS 2 properties.

And back to the very top: Access to the non-DOM [JS] property in an element is fundamentally different from access to the DOM property, and even more so to the DOM attribute in the same element. It is this fundamental difference and optimization (or lack) between approaches in browsers that explains the observed differences in performance.


1 IE 10 does some tricky tricks when calling a fake function is very fast (and I suspect the call was canceled), even though it has terrible access to JS properties. However, given that IE is a throwaway or just reinforcement, that calling a function is not something that introduces inherently slower behavior, it does not detract from my main argument: this access to the DOM is significantly lower.

2 I would like to say that access to DOM properties is slower, but FireFox does some amazing optimizations to input.value (but not img.src ). There is some special magic here. Firefox does not optimize access to DOM attributes.

And different browsers can have completely different results. However, I don’t think that you need to consider any “magic” with if or removeAttribute in order to at least isolate what I consider to be “performance”: actually using the DOM.

0
source share

All Articles