Javascript performance in the browser is arguably the most serious usability issue developers face. This problem is complicated by javascript blocking, the fact that most browsers use a single process to handle the user interface and JS script execution, so you can only do one thing at a time. The longer the js execution takes, the longer the browser waits for a response.

Load and execute

1. Improve the loading performance

  • 1.IE8,FF,3.5,Safari 4, and Chrome all allow parallel js files to be downloaded without blocking other scripts when a script downloads resources. But js downloads still block other resources, such as images. Although the script downloads don’t interact, the page still has to wait for all the JS code to download and execute before continuing. So there is still the problem of script blocking. It is recommended to place all JS files at the bottom of the body tag to reduce the impact on the entire page.

  • 2. Reducing the number of script files linked out of the page will improve page performance: HTTP requests introduce additional overhead, so downloading a single 300K file is more efficient than downloading 10 30K files.

  • 3. Dynamic script loading technology: whenever the download is started, the file is downloaded and executed without blocking other processes on the page.

function laodScript(url,callback){
    var script = document.createElement('script');
    script.type = 'text/javascript';

    if(script.readyState){  // ie
        script.onreadystatechange = function(){
            if(script.readyState == 'loaded' || script.readyState == 'complete'){
                script.onreadystatechange = null;
                callback()
            }
        }
    }else{ // Other browsers
        script.onload = function(){
            callback()
        }
    }
    script.src = url;
    document.getElementsByTagName('head') [0].appendChild(script);
}

/ / use
loadScript('./a.js'.function(){
    loadScript('./b.js'.function(){
        loadScript('./c.js'.function(){
            console.log('Loading complete')})})})Copy the code
  • 4. Non-blocking load class library — LABjs, use the following method:
<script src="lab.js"></script>
// Files are downloaded one at a time..wait() is used to specify which function to call after the file has been downloaded and executed
$LAB.script('./a.js')
    .script('./b.js')
    .wait(function(){
        App.init();
})

// In order to ensure the order of execution, a must be executed before B
$LAB.script('./a.js').wait()
    .script('./b.js')
    .wait(function(){
        App.init();
})

Copy the code

2. Data access and JS performance

1. In JS, where data is stored can have a significant impact on the overall performance of the code. There are four ways to store data: literals, variables, array entries, and object members. They have their own performance characteristics.

2. Accessing literals and local variables is the fastest. Conversely, accessing arrays and objects is slower

3. Since local variables exist at the beginning of the scope chain, accessing local variables is faster than accessing cross-scope variables

4. Avoid nested object members, which will significantly affect performance

5. The deeper a property or method is in the prototype chain, the slower it is to access it

6. Generally, we can save object members, array elements and cross-domain variables that need to be used many times in local variables to improve JS performance

3. The DOM programming

  • 1. Accessing the DOM affects browser performance. Modifying the DOM is more costly because it causes the browser to recalculate the geometric changes of the page. The usual approach is to reduce the number of DOM accesses and leave the operations on the JS side as much as possible.

Note: When updating a piece of HTML in the middle of a performance demanding operation, innerHTML is recommended because it runs fast in most browsers. But for most day-to-day operations, it doesn’t make much difference, so you should decide between innerHTML and createElement() based on a combination of readability, stability, team habits, and code style.

  • 2.HTML collection optimization

The HTML collection contains array-like objects referenced by DOM nodes that are always connected to the document, and you repeat the query every time you need the latest information, even if it’s just to get the number of elements in the collection.

1. Optimization 1 — Collection to array collToArr

function collToArr(coll){
    for(var i=0, a=[], len=coll.length; i<len; i++){
        a.push(coll[i]);
    }
    return a
}
Copy the code

2. Cache set length

3. Use local variables when accessing collection elements (cache repeated collection accesses into local variables and manipulate them with local variables)

  • 3. The traverse the DOM

1. Use apis that only return element nodes to traverse the DOM, because these apis are more efficient than their own implementations:

The property name Substituted property
children childNodes
childElementCount childNodes.length
firstElementChild firstChild
lastElementChild lastChild
nextElementSibling nextSibling
previousElementSibling previousSibling

The querySelectorAll() method takes a CSS selector as an argument and returns a NodeList — an array-like object containing matching nodes. This method does not return an HTML collection, so the returned nodes do not correspond to the real-time document structure, thus avoiding the performance problems associated with HTML collections.

let arr = document.querySelectorAll('div.warning, div.notice > p')
Copy the code
  • 4. Redraw and rearrange

After the browser downloads all the components of the page — HTML, JS, CSS, images, etc. — it parses and generates two internal data structures — the DOM tree and the render tree. Once the DOM tree and render tree are built, the browser starts to paint the page elements.

1. Conditions for rearrangement:

Add or remove visible DOM elements Position change element size change content change Page renderer initialization Browser window size change triggers an entire page reorder when the scroll bar appears

A rearrangement must redraw

  • 5. Render tree changes arrangement and refresh

Most browsers optimize the reordering process by queueing the changes and executing them in batches, whereas the operation of obtaining layout information results in a forced refresh of the queue.

offsetTop,offsetWidth...
scrollTop,scrollHeight...
clientTop,clientHeight...
getComputedStyle()
Copy the code

Some optimization suggestions: Separate the action of setting the style from the action of getting the style:

// Set the style
body.style.color = 'red';
body.style.fontSize = '24px'
// Read the style
let color = body.style.color
let fontSize = body.style.fontSize
Copy the code

In addition, get a compatible notation for the computed attribute:

function getComputedStyle(el){
    var computed = (document.body.currentStyle ? el.currentStyle : document.defaultView.getComputedStyle(el,' ');
    return computed
}
Copy the code
  • 6. Minimize redraws and rearrangements

1. Change styles in batches

/* Use cssText */
el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 20px';
Copy the code

2. Batch modify dom optimizations — take elements out of the document stream — apply multiple changes to them — bring elements back to the document

function appendDataToEl(option){
    var targetEl = option.target || document.body,
        createEl,
        data = option.data || [];
    // Remove the container from the document stream, reducing redrawing and rearranging
    var targetEl_display = targetEl.style.display;
    targetEl.style.display = 'none';

    // ***** Create document fragments to optimize Dom operations ****
    var fragment = document.createDocumentFragment();
    // Fill the element with data
    for(var i=0, max = data.length; i< max; i++){
        createEl = document.createElement(option.createEl);
        for(var item in data[i]){
            if(item.toString() === 'text'){
                createEl.appendChild(document.createTextNode(data[i][item]));
                continue;
            }
            if(item.toString() === 'html'){
                createEl.innerHTML = item,data[i][item];
                continue;
            }
            createEl.setAttribute(item,data[i][item]);
        }
        // **** Inserts the populated node into the document fragment ****
        fragment.appendChild(createEl);
    }
    // **** Insert document fragments into the target container ****
    targetEl.appendChild(fragment);
    // Display the container to complete the data filling
    targetEl.style.display = targetEl_display;
}

/ / use
var wrap = document.querySelectorAll('.wrap') [0];
var data = [
    {name: 'xujaing'.text: 'took'.title: 'xuanfij'},
    {name: 'xujaing'.text: 'took'.title: 'xuanfij'},
    {name: 'xujaing'.text: 'took'.title: 'xuanfij'}]; appendDataToEl({target: wrap,
    createEl: 'div'.data: data
});

Copy the code

The above optimization uses document fragments: when we insert a document fragment into a node, only the child nodes of the fragment are actually added, not the fragment itself. Dom manipulation can be made more efficient.

3. Cache layout information

// Cache the layout information
let current = el.offsetLeft;
current++;
el.style.left = current + 'px';
if(current > 300){
    stop();
}
Copy the code

4. Careful: hover

If a large number of elements use :hover, the corresponding speed will be reduced and the CPU will be increased

5. Use event delegates (implemented through event bubbling) to reduce the number of event handlers, reducing memory and processing time

function delegation(e,selector,callback){
    e = e || window.event;
    var target = e.target || e.srcElement;

    if(target.nodeName ! == selector || target.className ! == selector || target.id ! == selector){return;
    }
    if(typeof e.preventDefault === 'function'){
        e.preventDefault();
        e.stopPropagation();
    }else{
        e.returnValue = false;
        e.cancelBubble = true;
    }

    callback()
}
Copy the code

4. Algorithm and process control

1. Reduced attribute lookups and reversals in loops (50%-60% performance improvement)

/ / a for loop
for(var i=item.length; i--){
    process(item[i]);
}
/ / while loop
var j = item.length;
while(j--){
    process(item[i]);
}
Copy the code

2. Use the Duff device to optimize the loop (more on this in a later article)

3. Function-based iteration (slower than looping based iteration)

items.forEach(function(value,index,array){
    process(value);
})
Copy the code

4. Switch is usually faster than if-else, but it is not the best solution

5. String and regular expression

1. Other browsers, except IE, try to allocate more memory for the string to the left of the expression, and then simply copy the second string to its end. If the base string is on the far left in a loop, you can avoid duplicating a growing base string. Use [\s\ s] to match any string.

if(!String.prototype.trim){
    String.prototype.trim = function(){
        return this.replace(/^\s+/.' ').replace(/\s\s*$/.' ')}}Copy the code

6. A responsive user interface

1. The browser UI thread: the process used to execute javascript and update the user interface.

2. In Windows, the timer resolution is 15 milliseconds. Therefore, if the timer resolution is set to less than 15 milliseconds, Internet Explorer will be locked.

3. Split time-consuming tasks with delay arrays:

function multistep(steps,args,callback){
    var tasks = steps.concat();

    setTimeout(function(){
        var task = tasks.shift();
        task.apply(null, args || []);   // The call to Apply must be an array

        if(tasks.length > 0){
            setTimeout(arguments.callee, 25);
        }else{ callback(); }},25);
}
Copy the code

4. Batch processing tasks to record code running time:

function timeProcessArray(items,process,callback){
    var todo = item.concat();

    setTimeout(function(){
        var start = +new Date(a);do{
            process(todo.shift());
        }while(todo.length > 0 && (+new Date() - start < 50));

        if(todo.length > 0){
            setTimeout(arguments.callee, 25);
        }else{ callback(items); }},25)}Copy the code

5. Use Web Worker: It introduces an interface that allows code to run without taking up browser UI thread time. A Worker consists of the following parts:

  1. A Navigator object that includes appName,appVersion, User Agent, and Platform.

  2. A Location object, read only.

  3. A self object that points to the global worker object

  4. An importScripts() method to load the external JS file used by the worker

  5. All ECMAScript objects. Such as object, Array, the Date, etc

  6. XMLHttpRequest constructor

  7. SetTimeout (), setInterval ()

  8. A close() method that immediately stops the worker from running

  • Application scenarios
  1. Encode/decode large strings
  2. Complex mathematical operations (including image and video processing)
  3. Large array sort
// worker.js
var worker = new Worker('code.js');
// Receive the message
worker.onmessage = function(event){
    console.log(event.data);
}
// Send data
worker.postMessage('hello');

// code.js

// Import other computation code
importScripts('a.js'.'b.js');

self.onmessage = function(event){
    self.postMessage('hello' + event.data);
}
Copy the code

7. Ajax optimization

1. Five ways to request data from the server:

  1. XMLHttpRequest

  2. Dynamic Script Tag insertion

  3. iframes

  4. Comet (Server Push technology based on HTTP Persistent connection)

  5. Multipart XHR (allows a client to send multiple resources from a server to a client with a single HTTP request)

2. Simply send data to the server (beacons method) — beacons

// The only drawback is that the type of response received is limited
var url = '/req.php';
var params = ['step=2'.'time=123'];

(new Image()).src = url + '? ' + params.join('&');

// If you want to send data back to the listening server, you can do this in onLoad
var beacon = newImage(); beacon.src = ... ; beacon.onload =function(){... } beacon.onerror =function(){... }Copy the code

3. Some suggestions for Ajax performance

1. Cache data

  • 1. Set the Expires header on the server to ensure how long the browser caches the response (it must GET the request).
  • 2. The client caches the obtained information locally to avoid further requests

8. Programming practices

1. Avoid duplication of effort

// 1. Lazy loading
var a = (x,y) = >{
    if(x > 4){
        a = 0;
    }else{
        a = 1; }}// Call when needed
a();

// 2. Conditional preloading (applicable when the function executes immediately and frequently)
var b = a > 0 ? '4' : '0';
Copy the code

2. Use Object/Array literals

3. Use native methods

9. Build and deploy high-performance JS applications

When a Web browser requests a resource, it usually sends an Accept-Encoding HTTP header to tell the Web server which Encoding conversion type it supports. This information is used to compress documents for faster downloads and improve the user experience. The Accept – Encoding values are available including: gzip, deflate, compress, identity. If the Web server sees these headers in the request, it chooses the most appropriate Encoding and informs the Web browser of its decision through the Content-Encoding HTTP header.

2. Use the H5 offline cache

3. Use the CONTENT delivery network (CDN)

4. Analyze the page performance

// Check the code runtime
var Timer = {
    _data: {},
    start: function(key){
        Timer._data[key] = new Date(a); },stop: function(key){
        var time = Timer._data[key];
        if(time){
            Timer._data[key] = new Date() - time;
        };
        console.log(Timer._data[key]);
        return Timer._data[key]
    }
};
Copy the code

10. Browser cache

1. Add the Expires header

2. Use the cache-control cache-ontrol command to explain the browser cache mechanism

11. Compress components

1. Web clients can indicate support for compression through the Accept-Encoding header in HTTP requests

// Set the HTTP header on the browser request
Accept-Encoding: gzip
// The Web server responds by setting the HTTP header
Content-Encoding: gzip
Copy the code

2. Compression can reduce the amount of data in response by nearly 70%, so consider the compression of HTML, scripts, styles, and images

12. Causes of the white screen phenomenon

Browsers (such as Internet Explorer) do not render the page until the stylesheet is fully downloaded, resulting in a blank page. If the stylesheet is placed at the bottom of the page, the browser will take longer to download the stylesheet and will therefore display a white screen, so it is best to place the stylesheet in the head. The white screen is the browser’s fix to “unstyled flicker.” If the browser does not use the “white screen” mechanism and the page content is displayed step by step (for example, Firefox), the style sheet loaded later will cause the page to redraw and rearrange, which will incur the risk of page flickering.

13. Use one-time expressions for CSS expressions (but it’s best to avoid CSS expressions)

The execution function overrides itself when using A CSS expression

// css
p{
    background-color: expression(altBgcolor(this))}// js
function altBgcolor(el){
    el.style.backgroundColor = (new Date()).getHours() % 2 ? "#fff" : "#06c";
}
Copy the code

14. Reduce DNS lookups

1.DNS cache and TTL

1.DNS lookups can be cached to improve performance: THE DNS information stays in the OPERATING system's DNS cache (" DNS Client Services "on Microsoft Windows, and subsequent requests for the host name do not require much lookups2.TTL(Time to Live): This value tells the client how long the record can be cached. You are advised to set the TTL to one day// The average TTL received by a client from a DNS record is only half the maximum TTL because the time returned by the DNS parser is the remaining time of the TTL it recorded, and the TTL received changes each time a DNS lookup is performed for a given host name
3.Reduce DNS lookups by using keep-alive and fewer domain names4.It is generally recommended that page components be separated into at least2One, but not more4Host nameCopy the code

15. Avoid redirection

This section needs to cooperate with the front and back ends to unify the specification of page routing.

The last

Welcome to explore and build high-performance Web applications together, join us in the public account “Interesting talk front end” to discuss!

More recommended

  • Implementing a CMS full stack project from 0 to 1 based on nodeJS (Part 1)
  • Implementing a CMS full stack project from 0 to 1 based on nodeJS (middle)
  • Implement a CMS full stack project from 0 to 1 based on nodeJS (Part 2)
  • Implement server startup details for a CMS full stack project from 0 to 1 based on nodeJS
  • “Javascript advanced programming” core knowledge summary
  • With CSS3 to achieve stunning interviewers background that background animation (advanced source)
  • Remember an old project with cross-page communication issues and front-end implementation of file downloads
  • Write a mock data server using nodeJS in 5 minutes
  • JavaScript binary tree and binary search tree implementation and application
  • With JavaScript and C3 to achieve a turntable small game
  • Teach you to use 200 lines of code to write a love bean spell H5 small game (with source code)
  • Exploration and summary of front-end integrated solutions based on React/VUE ecology
  • How to write your own JS library in less than 200 lines of code
  • A picture shows you how to play vue-Cli3 quickly
  • 3 minutes teach you to use native JS implementation with progress listening file upload preview component
  • Developing travel List with Angular8 and Baidu Maps API
  • Js basic search algorithm implementation and 1.7 million data under the performance test
  • How to make front-end code 60 times faster
  • Vue Advanced Advanced series – Play with Vue and vuex in typescript