Home >Web Front-end >JS Tutorial >Introduction to JavaScript performance optimization methods (with examples)
This article brings you an introduction to JavaScript performance optimization methods (with examples). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you. help.
This article is mainly after I read "High Performance Javascript", I want to record some useful optimization solutions, and share some of my own experience with everyone,
Loading and execution of Javascript
As we all know, when the browser parses the DOM tree, when it parses the script tag, it will block all other tasks until the js file is downloaded. After the parsing execution is completed, execution will continue. Therefore, the browser will be blocked here at this time. If the script tag is placed in the head, the user can only see a blank page before the js file is loaded and executed. This user experience must be particularly bad. In this regard, the commonly used methods are as follows:
Place all script tags at the bottom of the body. This can ensure that the js file is loaded and executed last, and the page can be displayed first. to users. However, you must first know whether the first-screen rendering of the page depends on some of your js files. If so, you need to put this part of the js file on the head.
Use defer, such as the following writing. When using defer, although the browser will download the corresponding js file when it parses the tag, it will not execute it immediately. Instead, it will wait until the DOM is parsed (before DomContentLoader) before executing these js files. document. Therefore, the browser will not be blocked.
<script src="test.js" type="text/javascript" defer></script>
Dynamically load js files. In this way, you can load the required code after the page is loaded. You can also use this way. Implement lazy loading/on-demand loading of js files. For example, it is more common now that webpack is combined with vue-router/react-router to achieve on-demand loading. The corresponding code is only loaded when a specific route is accessed. The specific method is as follows:
1. Dynamically insert script tags to load scripts, such as through the following code
function loadScript(url, callback) { const script = document.createElement('script'); script.type = 'text/javascript'; // 处理IE if (script.readyState) { script.onreadystatechange = function () { if (script.readyState === 'loaded' || script.readyState === 'complete') { script.onreadystatechange = null; callback(); } } } else { // 处理其他浏览器的情况 script.onload = function () { callback(); } } script.src = url; document.body.append(script); } // 动态加载js loadScript('file.js', function () { console.log('加载完成'); })
2. Load js files through xhr, but through In this way, you may face cross-domain problems. Examples are as follows:
const xhr = new XMLHttpRequest(); xhr.open('get', 'file.js'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) { const script = document.createElement('script'); script.type = 'text/javascript'; script.text = xhr.responseText; document.body.append(script); } } }
3. Merge multiple js files into one and compress them. Reason: Most browsers currently support parallel downloading of js files, but there is still a certain limit on the number of concurrent downloads (based on the browser, some browsers can only download 4), and each js file needs to create an additional With an http connection, loading four 25KB files takes longer than loading one 100KB file. Therefore, our best option is to merge multiple js files into one and compress the code.
When a function is executed, an execution context will be generated. This execution context defines the environment when the function is executed. When the function completes execution, the execution context will be destroyed. Therefore, calling the same function multiple times results in the creation of multiple execution contexts. Each execution context has its own scope chain. I believe everyone should have known about scope for a long time. For a function, its first scope is the variables inside its function. During function execution, every time a variable is encountered, the scope chain of the function will be searched to find the first matching variable. It first searches for variables inside the function, and then searches layer by layer along the scope chain. Therefore, If we want to access the outermost variables (global variables), it will cause a relatively large performance loss compared to directly accessing the internal variables. Therefore, we canstore frequently used global variable references in a local variable.
const a = 5; function outter () { const a = 2; function inner () { const b = 2; console.log(b); // 2 console.log(a); // 2 } inner(); }
In JavaScript, there are four main types: literals, local variables, array elements and objects. Accessing literals and local variables is the fastest, while accessing array elements and object members is relatively slow. When accessing object members, just like the scope chain, the search is performed on the prototype chain. Therefore, if the searched member is too deep in the prototype chain, the access speed will be slower. Therefore, we should reduce the number of lookups and nesting depth of object members as much as possible . For example, the following code
// 进行两次对象成员查找 function hasEitherClass(element, className1, className2) { return element.className === className1 || element.className === className2; } // 优化,如果该变量不会改变,则可以使用局部变量保存查找的内容 function hasEitherClass(element, className1, className2) { const currentClassName = element.className; return currentClassName === className1 || currentClassName === className2; }
minimizes the number of DOM operations, uses JavaScript to process it as much as possible, and uses local variables to store DOM nodes as much as possible . For example, the following code:
// 优化前,在每次循环的时候,都要获取id为t的节点,并且设置它的innerHTML function innerHTMLLoop () { for (let count = 0; count < 15000; count++) { document.getElementById('t').innerHTML += 'a'; } } // 优化后, function innerHTMLLoop () { const tNode = document.getElemenById('t'); const insertHtml = ''; for (let count = 0; count < 15000; count++) { insertHtml += 'a'; } tNode.innerHtml += insertHtml; }
Reduce reordering and redrawing as much as possible. Rearrangement and redrawing may be very expensive. Therefore, in order to reduce reordering We can make the following optimizations to eliminate the number of re-merging occurrences
1. When we want to modify the style of the Dom, we should merge all the modifications as much as possible and make them once processing to reduce the number of rearrangements and re-remits.
// 优化前 const el = document.getElementById('test'); el.style.borderLeft = '1px'; el.style.borderRight = '2px'; el.style.padding = '5px'; // 优化后,一次性修改样式,这样可以将三次重排减少到一次重排 const el = document.getElementById('test'); el.style.cssText += '; border-left: 1px ;border-right: 2px; padding: 5px;'
2.当我们要批量修改DOM节点的时候,我们可以将DOM节点隐藏掉,然后进行一系列的修改操作,之后再将其设置为可见,这样就可以最多只进行两次重排。具体的方法如下:
// 未优化前 const ele = document.getElementById('test'); // 一系列dom修改操作 // 优化方案一,将要修改的节点设置为不显示,之后对它进行修改,修改完成后再显示该节点,从而只需要两次重排 const ele = document.getElementById('test'); ele.style.display = 'none'; // 一系列dom修改操作 ele.style.display = 'block'; // 优化方案二,首先创建一个文档片段(documentFragment),然后对该片段进行修改,之后将文档片段插入到文档中,只有最后将文档片段插入文档的时候会引起重排,因此只会触发一次重排。。 const fragment = document.createDocumentFragment(); const ele = document.getElementById('test'); // 一系列dom修改操作 ele.appendChild(fragment);
3.使用事件委托:事件委托就是将目标节点的事件移到父节点来处理,由于浏览器冒泡的特点,当目标节点触发了该事件的时候,父节点也会触发该事件。因此,由父节点来负责监听和处理该事件。
那么,它的优点在哪里呢?假设你有一个列表,里面每一个列表项都需要绑定相同的事件,而这个列表可能会频繁的插入和删除。如果按照平常的方法,你只能给每一个列表项都绑定一个事件处理器,并且,每当插入新的列表项的时候,你也需要为新的列表项注册新的事件处理器。这样的话,如果列表项很大的话,就会导致有特别多的事件处理器,造成极大的性能问题。而通过事件委托,我们只需要在列表项的父节点监听这个事件,由它来统一处理就可以了。这样,对于新增的列表项也不需要做额外的处理。而且事件委托的用法其实也很简单:
function handleClick(target) { // 点击列表项的处理事件 } function delegate (e) { // 判断目标对象是否为列表项 if (e.target.nodeName === 'LI') { handleClick(e.target); } } const parent = document.getElementById('parent'); parent.addEventListener('click', delegate);
The above is the detailed content of Introduction to JavaScript performance optimization methods (with examples). For more information, please follow other related articles on the PHP Chinese website!