High-performance javascript--efficient data access

Source: Internet
Author: User
Tags object object javascript array

Next, I would like to write a high-performance JavaScript topic.

First: a non-blocking loading strategy for high-performance javascript--scripts .

A problem with classic computer science is where the data should be stored to achieve the best read and write efficiency. Whether the data is stored properly is related to the speed at which data is retrieved during code execution. In JavaScript, this problem is relatively straightforward, because there are only a few ways to choose the data representation. In JavaScript, there are four basic data access locations:

    • Literal Values Direct Volume
      • The direct volume represents only itself, not in a particular location.
      • The direct amounts of JavaScript include: strings (strings), Numbers (numbers), Boolean values (Booleans), Objects (objects), arrays (arrays), functions (functions), regular expressions (regular expressions), a null value with a special meaning (null), and undefined (undefined).
    • Variables variable
      • Developers use the VAR keyword to create a value for storing data.
    • Array items
      • Has a numeric index that stores a JavaScript array object.
    • Object Members
      • Has a string index that stores a JavaScript object.

Each data storage location has a specific load of read and write operations. In most cases, the performance difference in data access to a direct volume and a local variable is negligible. In particular, access to array items and object members is more expensive and much more highly dependent on the browser. The general recommendation is that if you care about running speed, use direct and local variables as much as possible, limiting the use of array items and object members. To do this, there are several patterns to avoid and optimize our code:

Managing Scope Management Scopes

The scope concept is the key to understanding JavaScript, and the scope has a huge impact on JavaScript, both in terms of performance and functionality. To understand the relationship between run speed and scope, first understand how scopes work.

Scope Chains and Identifier Resolution scope chain and identifier resolution

Each JavaScript function is represented as an object, which is an instance of a function. It contains the accessible properties of our programming definition, and a series of internal properties that cannot be accessed by the program and is used only by the JavaScript engine, where an internal property is [[Scope]], defined by the ECMA-262 standard third edition.

The internal [Scope] property contains a collection of objects in the scope in which a function is created. This collection is called the scope chain of the function, and it determines which data can be accessed by the function. Each object in the scope chain in this function is called a mutable object, expressed as a "key-value pair." When a function is created, its scope chain is populated with objects that represent the data accessible in the environment in which this function was created:

123  return sum; 4 }

When the Add () function is created, its scope chain is filled with a single Mutable object that represents all global scope defined variables. This global object contains access interfaces such as Windows, browsers, and documents. As shown: (The scope chain of the Add () function, note that only a very small part of the global variable is drawn here)

The scope chain of the Add function will be used at run time, assuming the following code is running:

1 var total = Add (5,10);

When you run this add function, an internal object is created, called the runtime context, and a run-time context defines the environment in which a function is run. Execution And for each individual run, each run-time context is independent, and multiple invocations produce more of this creation. The run-time context is destroyed when the function is executed.

A run-time context has its own scope chain, which is used to resolve identifiers. When the run-time context is created, its scope is initialized, along with the objects contained by the run function's scope chain [[Scope] property. These values are copied into the scope chain of the run-time context, in the order in which they appear in the function. Once the work is done, a new object called the "active object" is in place to create the run-time context. This activation object acts as a Mutable object for the duration of the function, and includes access to all local variables, named parameters, parameter sets, and this interface. This object is then pushed into the forefront of the scope chain. When the scope chain is destroyed, the active object is also destroyed together. as follows: (the scope chain when running Add ())

In the process of running a function, identifier recognition is performed for each variable encountered. Identifier recognition this process depends on where to get the data or access the data. This procedure searches the scope chain for the run-time context and finds an identifier with the same name. The search work starts from the scope front end of the activation target that runs the function. If found, the variable with the specified identifier is used, and if not found, the search will enter the next object in the scope chain, which continues to run until the identifier is found or no more available objects are available for the search, which is considered an undefined identifier. It is this search process that affects performance.

Identifier Resolution Performance Identifier recognition performance

Identifier recognition is energy-intensive.

In the scope chain of a run-time context, the deeper the identifier is in, the slower it reads and writes. As a result, local variables in the function are always accessed at the fastest speed, while global variables are usually the slowest (optimizing the JavaScript engine, such as safari can change this situation in some cases).

Keep in mind that global variables are always at the last position of the run-time context chain, so they are always the farthest to be accessed. A good rule of thumb is to use local variables to store variable values outside the local scope if they are used more than once in a function. Consider the following example:

1 function Initui () {2 var bd = document.body,3 links = document.getelementsbytagname ("a"),4 i = 0,5 len = links.length;6     7while (i<Len){8 Update (links[i++]);9 }Ten      One document.getElementById ("go-btn"). OnClick= function () { A       start (); - }; -      the Bd.classname= "Active";  - }

This function contains three references to the document, and document is a global object. To search to document, you must traverse the entire scope chain until it is finally found. Use the following methods to mitigate the performance impact of repeated global variable access:

1 function Initui () {2 var doc=document,3 bd = doc.body,4 links = doc.getelementsbytagname ("a"),5 i = 0,6 len = links.length;7     8while (i<Len){9 Update (links[i++]);Ten } One      A Doc.getelementbyid ("go-btn"). OnClick= function () { -       start (); - }; the      - Bd.classname= "Active";  - }

Using Doc instead of document is faster because it is a local variable. Of course, this simple function does not show a huge performance improvement, because of the number of reasons, but it can be imagined that if the dozens of all variables are repeatedly accessed, then the performance improvement will be very good.

Scope Chain Augmentation Change scope chain

For one, the scope chain of a run-time context is not changed. However, there are two types of expressions that can temporarily change the runtime context at run time. The first one is the WITH expression:

1 function Initui () {2 With (document) {//avoid!3 var bd = body,4 links = getElementsByTagName ("a"),5 i = 0,6 len = links.length;7       8while (i<Len){9 Update (links[i++]);Ten       } One          A getElementById ("go-btn"). OnClick= function () { -         start (); -       }; the      - Bd.classname= "Active";  -   } - }

This rewritten version uses a with expression to avoid writing "document" multiple times. This may seem more efficient, but in reality, there is a performance problem.

When the code flow executes into a with expression, the scope of the run-time context is temporarily changed. A new Mutable object is created that contains all the properties of the specified object (for this example, the Document object). This object is inserted at the forefront of the scope chain. This means that all local variables of the function are now pushed into the second scope chain object, so the access cost of the local variable becomes higher.

Formally for this reason, it is best not to use the with expression. This is not worth the candle. As mentioned earlier, a performance boost can be achieved simply by storing the document in a local variable.

Another thing that can change the run-time context is the try-catch sentence catch with the same effect. When a try block error occurs, the program automatically goes into the catch block and pushes all local variables into the second scope chain object, so long as the catch block executes, the scope chain returns to its original state.

12    methodthatmightcauseanerror (); 3 } catch (ex) {4    alert (ex.message);//scope chain changed here 5 }

If used properly, the try-catch expression is a very useful statement, so it is not recommended to avoid it altogether. But a try-catch statement should not be a workaround for JavaScript errors, and if you know that an error occurs frequently, you should modify the code itself. Don't you?

  

Dynamic scope

Either the WITH expression or the clause catch of the Try-catch expression, and the function that contains () are considered dynamic scopes. A dynamic scope is generated as a result of code runs, so it is not possible to determine whether a dynamic scope exists by static analysis (by looking at the code). For example:



   return window;} var w = subroutine (); What is the value of W? };

The Execute () function looks like a dynamic scope because it uses (). The value of the W variable is related to the incoming code code. In most cases, W will be equivalent to the Global Window object. But if the incoming is:

1 Execute ("var window = {};");

In this case, the () creates a local window variable in the Execute () function. So W will be equivalent to this local window variable instead of the one of the global window. So not running this code is impossible to predict the final situation, the exact meaning of the identifier window can not be known beforehand.

Therefore, the use of dynamic scopes is only recommended at absolutely necessary times.

Closure,scope,and memory closure, scope, and RAM

Closures are one of the most powerful aspects of JavaScript, allowing functions to access data outside the local scope. To understand the performance issues associated with closures, consider the following example:

1 function assignevents () {23  document.getElementById ("save-btn"). onclick = function (event) {45  }; 6 }

The assignevents () function specifies an event handling handle for the DOM element. This event handler is a closure that can access the ID variable within its scope when the function execution is created. This method closes the access to the ID variable and must create a specific scope chain.

When the assignevents () function executes, an activation object is created and contains some due content, which contains the ID variable. It becomes the first object on the run-time context chain, and the global object is the second. When a closure is created, the [Scope] property is initialized with these objects, such as:

Because the closure's [Scope] property contains an object reference that is the same as the run-time context scope chain, there are side effects, and typically, a function's activation object is destroyed with the run-time context. When a closure is involved, the activation object cannot be destroyed because it still exists in the [Scope] property of the closure. This means that the closure in the script requires more memory overhead than the non-closure function. Especially in IE, using non-native JavaScript objects to implement DOM objects, closures can lead to memory leaks.

When a closure is executed, a run-time context is created, its scope chain is initialized at the same time as the two same scope chain referenced in [Scope], and a new activation object is created for the closure itself. Such as:

As you can see, the ID and savedocument two identifiers exist at the position after the first object in the scope chain. This is the main performance concern of closures: you often access identifiers that are outside the range, and each access results in some performance penalty.

The best way to use closures in scripts is to be aware of the memory and running speed. However, you can do this by storing the usual extraterritorial variables in local variables, and then accessing the local variables directly.

Object Members

Object members include properties and methods, and in JavaScript, they differ very slightly. A named member of an object can contain any data type. Since a function is also an object, object members can contain functions in addition to the traditional data types. When a named member refers to a function, it is called a "method", and a non-function type of data is called a "property".

As previously stated, access to object members is slower than direct and local variable access, and in some browsers it is slower than accessing an array, which is related to the nature of the object in JavaScript.

Prototype prototypes  

The objects in JavaScript are prototype-based, and an object is bound to its prototype through an internal property. Firefox,safari and chrome Open this property to developers, called _proto_. Other browsers do not allow scripts to access this property. Any time we create an implementation of a built-in type, such as an object or array, these instances automatically have an object as their prototype. objects can have two types of members: instance members and prototype members. Instance members exist directly on the instance itself and the prototype member inherits from the object. Consider the following example:

1 var book = {2  title: ' High Performance JavaScript ',34}; 5 alert (book.tostring ()); "[Object Object]"

In this code, book has a title and publisher two instance members. Note that it does not define the ToString () interface, but the interface is called and no error is thrown. The toString () function is a prototype member of a book that inherits from a prototype object. Indicate their relationship:

The process of working with object members is very similar to processing variables. When Book.tostring () is called, a search for the member named "ToString" begins with the object instance, and if there is no member named ToString, it is turned to the search prototype object, where the ToString () method is found and executed. In this way, book can access every property and method owned by its prototype.

We can use the hasOwnProperty () function to determine whether an object has an instance member with a specific name. Instance slightly.

Prototype Chains prototype Chain

The prototype of an object determines the type of an instance. By default, all objects are instances of object and inherit all the basic methods. such as ToString (). We can also use constructors to create another prototype. For example:

1 function Book (title, publisher) {2 this.title = title;3 this.publisher = publisher;4 }5 6 Book.prototype.sayTitle = function () {7 alert (this.title);8 };9 var book1 = new book ("High Performance JavaScript", "Prototype Chains");Ten var book2 = new book ("Javascript:the Good Parts", "Prototype Chains"); One Alert (Book1 instanceof book);//true A alert (Book1 instanceof Object);//true - book1.saytitle ();//"High performance JavaScript" -Alert (book1.tostring ()); "[Object Object]"

The book constructor is used to create a new book instance Book1. Book1 's prototype (_PROTO_) is Book.prototype,book.prototype's prototype is object. This creates a prototype chain.

Note that Book1 and BOOK2 share the same prototype chain. Each instance has its own title and publisher properties, and the other members inherit from the prototype. And as you suspect, the deeper the prototype chain, the slower the search will be, especially IE, which will increase the performance penalty every step of the way into the prototype chain. Remember that the process of searching instance members is heavier than accessing direct and local variables, so increasing the overhead of traversing the prototype chain just magnifies the effect.

  

Nested members nested member

Because an object member may contain other members. For example, window.location.href (Gets the URL of the current page) this mode. Every time you encounter a good dot,javascript the engine will perform a parsing process on the object member, and the deeper the nesting of the members, the slower the access speed. Location.href is always faster than window.location.href, while the latter is faster than window.location.href.toString (). If these properties are not instance members of an object, then member resolution also searches the prototype chain at each point, which will take more time.

Summary Summary

    • In JavaScript, the location of the data store can have a significant impact on the overall performance of the code. There are four types of data access: direct volume, variable, array item, object member. We have different performance considerations for them.
    • Direct and local variables are accessed very quickly, and array items and object members take longer.
    • A local variable is faster than an external variable because it is in the first object in the scope chain. The deeper the variable is positioned in the scope chain, the longer it takes to access it. The global variable is always the slowest because it is in the last loop of the scope chain.
    • Avoid using the with expression because it alters the scope chain of the run-time context. The catch clause of the Try-catch statement should be treated with special care, and it has the same effect.
    • Nested object members can cause significant performance impact and are used sparingly.
    • In general, we store frequently used object members, array items, and extraterritorial variables in local variables. The local variables are then accessed faster than those of the original variables.

 

With these strategies, you can greatly improve the actual performance of Web applications that use JavaScript code.

Refer to the book "High Performance JavaScript".

High-performance javascript--efficient data access

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.