In JavaScript, we should use local variables instead of global variables as much as possible. Everyone knows this sentence, but who said it first? Why do this? Is there any basis for this? If you don't do this, how much loss will it cause to performance? This article will explore the answers to these questions and fundamentally understand what factors are related to the reading and writing performance of variables.
【Original】JavaScript variable performance
【Author】Nicholas C. Zakas
[Translation] In JavaScript, why should we use local variables whenever possible?
[Translator] Mingda
The following is a translation of the original text:
On the issue of how to improve JavaScript performance, the most commonly heard suggestion is to use local variables instead of global variables. This is advice that has stuck with me and never questioned it in my nine years of working in web development, and it's based on JavaScript's handling of scoping and identifier resolution. (identifier resolution) method.
First of all, we need to make it clear that functions are embodied as objects in JavaScript. The process of creating a function is actually the process of creating an object. Each function object has an internal property called [[Scope]], which contains the scope information when the function was created. In fact, the [[Scope]] attribute corresponds to a list of objects (Variable Objects), and the objects in the list can be accessed from within the function. For example, if we create a global function A, then A's [[Scope]] internal property contains only one global object (Global Object), and if we create a new function B in A, then B's [[Scope] ] attribute contains two objects, the Activation Object object of function A is in the front, and the global object (Global Object) is in the back.
When a function is executed, an executable object (Execution Object) is automatically created and bound to a scope chain (Scope Chain). The scope chain will be established through the following two steps for identifier resolution.
1. First, copy the objects in the internal properties of the function object [[Scope]] to the scope chain in order.
2. Secondly, when the function is executed, a new Activation Object object will be created. This object contains the definitions of this, parameters (arguments), and local variables (including named parameters). This Activation Object object will be placed in action. The front of the domain chain.
During the execution of JavaScript code, when an identifier is encountered, it will be searched in the scope chain of the execution context (Execution Context) based on the name of the identifier. Starting from the first object in the scope chain (the Activation Object of the function), if not found, search for the next object in the scope chain, and so on, until the definition of the identifier is found. If the last object in the scope, which is the Global Object, is not found after searching, an error will be thrown, prompting the user that the variable is undefined. This is the function execution model and identifier resolution (Identifier Resolution) process described in the ECMA-262 standard. It turns out that most JavaScript engines are indeed implemented this way. It should be noted that ECMA-262 does not mandate the use of this structure, but only describes this part of the function.
After understanding the process of identifier resolution (Identifier Resolution), we can understand why local variables are resolved faster than variables in other scopes, mainly because the search process is greatly shortened. But how much faster will it be? To answer this question, I simulated a series of tests to test the performance of variables at different scope depths.
The first test is to write the simplest value to a variable (the literal value 1 is used here). The result is shown in the figure below, which is very interesting:
It is not difficult to see from the results that when the identifier parsing process requires deep search, there will be a performance loss, and the degree of performance loss will increase with the increase of the identifier depth. Unsurprisingly, Internet Explorer performed the worst (but to be fair, there were some improvements in IE 8). It is worth noting that there are some exceptions here, Google Chrome and the latest midnight version of WebKit have a very stable access time to variables and do not increase with increasing scope depth. Of course, this should be attributed to the next generation JavaScript engines they use, V8 and SquirrelFish. These engines perform optimizations when executing code, and it's clear that these optimizations make accessing variables faster than ever before. Opera also performed well, being much faster than IE, Firefox and the current version of Safari, but slower than browsers based on V8 and Squirrelfish. The performance of Firefox 3.1 Beta 2 is a bit unexpected. The execution efficiency of local variables is very high, but as the number of scope layers increases, the efficiency is greatly reduced. It should be noted that I am using the default settings here, which means that Firefox does not have the Trace function turned on.
The above results were obtained by performing write operations on variables. In fact, I was curious whether the situation would be any different when reading variables, so I did the following test. It was found that the reading speed is slightly faster than the writing speed, but the trend of performance changes is consistent.
As in the previous test, Internet Explorer and Firefox were still the slowest, and Opera showed very eye-catching performance. Similarly, Chrome and the latest version of Webkit Midnight Edition showed performance trends that have nothing to do with scope depth. It is also worth paying attention to. Yes, the variable access time in Firefox 3.1 Beta 2 still has a strange jump with depth.
During the test, I discovered an interesting phenomenon, which is that Chrome will have additional performance losses when accessing global variables. The time to access global variables has nothing to do with the scope level, but it will be 50% longer than the time to access local variables of the same level.
What enlightenments can these two tests bring us? The first is to verify the old point of view, which is to use local variables as much as possible. In all browsers, accessing local variables is faster than accessing variables across scopes, including global variables. The following points should be the experience gained through this test:
* Carefully check all variables used in the function. If there is a variable that is not defined in the current scope and is used more than once, then we should save this variable In a local variable, use this local variable to perform read and write operations. This can help us reduce the search depth of variables outside the scope to 1. This is especially important for global variables, because global variables are always searched at the last position of the scope chain.
* Avoid using the with statement. Because it will modify the scope chain of the execution context (Execution Context) and add an object (Variable Object) at the front. This means that during the execution of with, the actual local variables are moved to the second position on the scope chain, which will cause a performance loss.
* If you are sure that a piece of code will definitely throw an exception, then avoid using try-catch, because the catch branch is processed in the same scope chain as with. However, there is no performance loss in the try branch code, so it is still recommended to use try-catch to catch unpredictable errors.
If you want more discussion around this topic, I gave a small talk at the Mountain View JavaScript Meetup last month. You can download the slides on SlideShare, or watch the full video of the party, which starts around the 11-minute mark of my talk.
Translator’s Notes:
If you have any doubts while reading this article, I suggest you read the following two articles:
* "JavaScript Object Model-Execution Model" written by Richie
* "ECMA-262 Third Edition", mainly look at Chapter 10, which is the Execution Context. The terms mentioned in this article are explained in detail there.
At the end, Nicholas mentioned a Mountain View JavaScript Meetup. The Meetup website is actually an organization website for various real-world activities. You need to bypass the firewall to access it. Living in California is really a blessing. There are so many good activities to participate in. hehe.