A comprehensive summary of Javascript performance

  • 2020-03-26 23:07:50
  • OfStack

Javascript is a very flexible language, we can write all kinds of code at will, different styles of code is also bound to lead to differences in execution efficiency, the development process is scattered contact with many methods to improve the performance of the code, sorting out the usual more common and easy to avoid problems

Javascript itself performs efficiently
Javascript features such as scoped chains, closures, prototype inheritance, and eval provide all sorts of magical functionality, but they also pose all sorts of efficiency problems, which can lead to poor performance if used carelessly.

1. Global import
We will use more or less in the process of encoding to some global variables (window, the document, the custom global variables, etc.), understand javascript scope chain knows, in access to global variables, the local scope need to traverse the entire layer scope chain until top scope, and more efficient access to a local variable will be faster, so the high frequency of the local scope when using some global objects can be imported into the local scope, such as:


  //1. Pass in the module as a parameter
  (function(window,$){
      var xxx = window.xxx;
      $("#xxx1").xxx();
      $("#xxx2").xxx();
  })(window,jQuery);

  //2. Store local variables temporarily
  function(){
    var doc = document;
     var global = window.global;
 } 

Eval and the eval problem
We all know that eval can treat a string as js code, and it is said that code executed with eval is more than 100 times slower than code executed without eval.

JavaScript code before implementation will be similar to the precompiled operation: first of all, will create a current execution environment of active objects, and those who use the var statement variable is set to the activities of the object's properties, but the variable assignment is undefined, and defines the function to the attributes of the object function is also added as activity, and it is function definition of their values. However, if you use "eval", the code in "eval" (which is really a string) cannot recognize its context in advance, cannot be parsed and optimized in advance, or cannot be precompiled. Therefore, its performance will be greatly reduced

In fact, you don't usually use eval these days. What I want to talk about here is the scenario of two eval classes (new Function{},setTimeout,setInterver).

SetTimtout (" alert (1) ", 1000);
SetInterver (" alert (1) ", 1000);
"(new Function (" alert (1))) ();

All of the above types of code are inefficient, so it is recommended to directly pass in an anonymous method, or a method reference, to the setTimeout method

3. When the closure ends, variables that are no longer referenced are released


  var f = (function(){
    var a = {name:"var3"};
    var b = ["var1","var2"];
    var c = document.getElementByTagName("li");
    //**** other variables
    //*** some operations
    var res = function(){
        alert(a.name);
    }
    return res;
})() 

The return value of a variable in the code above f is composed of an immediate execution function closures in the res returned by the method, the variable retained for all variables in the closure (a, b, c, etc.), so the two variables will always reside in memory space, especially for dom element references to memory consumption will be very big, and we use only to a variable's value in the res, therefore, before the closure back our other variables can be released

  var f = (function(){
    var a = {name:"var3"};
    var b = ["var1","var2"];
    var c = document.getElementByTagName("li");
    //**** other variables
    //*** some operations
    //The closure releases variables that are no longer used before returning
    b = c = null;
    var res = function(){
        alert(a.name);
        }
    return res;
})() 

The efficiency of Js manipulation of the dom
In the process of web development, the bottleneck of front-end execution efficiency is often dom operation, which is a very performance consuming thing. How to save performance as much as possible in the process of dom operation?

1. Reduce reflow
What is reflow?
When the attributes of a DOM element change, such as color, the browser tells render to repaint the corresponding element, a process called repaint.

If the change involves an element layout (such as width), the browser abandons the original attributes, recalculates and passes the result to render to redepict the page element, a process called reflow.

Ways to reduce reflows
1. First delete the element from the document, and then put the element back to the original position after the modification (only when a large number of reflow operations are carried out on an element and its child elements, can the effect of 1,2 methods be more obvious)

2. Set the display of the element to "none", and then change the display to its original value

3. When modifying multiple style attributes, define the class class instead of modifying the style attribute for certain.

Use a documentFragment when adding a lot of elements to a page

For example,


for(var i=0;i<100:i++){
    var child = docuemnt.createElement("li");
    child.innerHtml = "child";
    document.getElementById("parent").appendChild(child);
} 

The above code operates on the dom multiple times, which is inefficient. Instead, you can create a documentFragment in the following form, add all the elements to the docuemntFragment without changing the dom structure, and finally add it to the page with only one reflow

var frag = document.createDocumentFragment();
for(var i=0;i<100:i++){
        var child = docuemnt.createElement("li");
        child.innerHtml = "child";
    frag.appendChild(child);
}
document.getElementById("parent").appendChild(frag); 

2. Temporary storage of dom state information
When the state information of an element needs to be accessed multiple times in the code, we can temporarily store it in a variable with the state unchanged, so as to avoid the memory overhead caused by multiple dom accesses. A typical example is:

var lis = document.getElementByTagName("li");
for(var i=1;i<lis.length;i++){
    //***
}

The above method will access the dom elements in every loop, and we can simply optimize the code as follows

var lis = document.getElementByTagName("li");
for(var i=1,j=lis.length ;i<j;i++){
    //***
} 

3. Narrow down the search scope of the selector
When looking for dom elements, try to avoid large area traversal of page elements, use precision selectors, or specify a context to narrow the search, as in jquery

The & # 8226; Use less fuzzy matching selectors: for example, $(" [name*='_fix'] "), and more like id and a narrowing down of the compound selector $(" li.active ")

The & # 8226; Specify context: for example $(" # parent.class "),$(".class ",$el), etc

4. Use event delegates
Usage scenario: a list with a large number of records, each record needs to bind the click event, after the mouse click to achieve some functions, we usually do is to bind the monitoring event for each record, this practice will lead to a large number of event listeners on the page, which is inefficient.

Basic principles: We all know that events bubble in the dom specification, meaning that without actively preventing them from bubbling, the events of any element bubble up to the top of the dom tree. The event object also provides an event.target (srcElement under IE) to point to the event source, so we can find the original element that triggered the event even if we listen on the parent element. This is the basic principle of delegation. Without further ado, the above example


  $("ul li").bind("click",function(){
    alert($(this).attr("data"));
}) 

This is done by attaching a click event to all li elements to listen for mouse clicks on each element, so that there are a lot of event listeners on the page.

Let's rewrite the principle of listening for events as described above


  $("ul").bind("click",function(e){
    if(e.target.nodeName.toLowerCase() ==="li"){
        alert($(e.target).attr("data"));
    }
}) 

In this way, we can just add an event listener to capture all the events that are triggered on the li and do the corresponding actions.

Of course, we don't have to judge the source of the event every time, but we can abstract it off to the utility class to do. The delegate() method in jquery does this

Grammar is such a $(selector). The delegate (childSelector, event, data, function), such as:

  $(" div "). The delegate (" button ", "click", function () {
  $(" p "). SlideToggle ();
});

Parameter description (quoted from w3school)

parameter describe childSelector A necessity. Specifies that one or more child elements of an event handler are to be attached. The event A necessity. Specifies one or more events to attach to an element. Multiple event values are separated by Spaces. It has to be a valid event. The data Optional. Specifies the additional data passed to the function. The function A necessity. Specifies the function to run when an event occurs.

Another benefit of the Tips: event delegates is that you can listen for events that fire on elements that are dynamically added after the event binding, so you don't have to bind events to an element every time it is dynamically added to the page.


Related articles: