As a weakly typed language, JS has a unique prototype chain mechanism and a set of DOM and BOM interfaces in the host, which increases the complexity of its performance control. JavaScript is still primarily used in the browser, so how it behaves in the browser is still important. This paper will start from the author’s practical experience, respectively from the loading and parsing, syntax optimization, DOM operation and other aspects of the summary of excellent JS code performance optimization strategy. At the same time, focus on how to write more elegant and clean JS code.
Load the parsing
Loading and parsing of JS files involves the browser’s parsing and rendering strategy for documents. Some bad document structure will lead to empty screen rendering, lag, and even page chaos. For JS, in the loading and parsing stage can be optimized from the following aspects.
- Bring in the JS file at the end (before) of the document
Javascript code introduces page loading through the
- Merging JS files
Reducing HTTP requests is the most common performance optimization strategy. Importing four 10 KB files requires four requests, which is more performance intensive than importing one 40kb file, so when there are too many JS files to import, the necessary script merge is necessary.
However, if a file is too large, it will take too long to parse, which is not worth the cost.
- Use defer to download the script without blocking
Defer is an attribute provided in the standards for the
By the way, there is another property async that can be applied to
Grammar to optimize
- Be careful with global variables
Global variables have longer search scope chains, longer life cycles, and the risk of memory leaks and even unexpected bugs. Third party libraries in your project usually expose global variables, which may conflict with your declared global variables. So, use global variables as sparingly as possible.
After ES6, it was better to declare variables using let/const.
- Use better performance traversal operations
After testing, the time of cyclic operation in JS ranked from small to large: for- > forEach/for-of -> for-in
In other words, for large-scale traversal operations, the for loop is preferred, followed by forEach and for-of, which are in the same order of magnitude. The slowest one is for-IN, which is slow because it is often used for traversal of object attributes. It also accesses its own properties and the properties of its stereotype chain (including non-enumerable properties).
- Avoid using with and eval
With can change the current scope by pushing an object into the head of the scope chain, which makes it less efficient to access local variables within the scope.
Eval treats an incoming string as a script, which greatly reduces script execution performance and is therefore avoided.
- Use closures as little as possible
Closures provide some convenience, but they also have a performance impact by retaining variable references that should have been reclaimed, increasing the length of the scope chain and affecting performance.
It also runs the risk of memory leaks.
- Do not modify the stereotype methods of reference types
Modifying the prototype approach is likely to have an unpredictable impact on teamwork, so try to avoid it.
- Switch is preferred over if-else when a large number of values are judged
When there are too many criteria, such as more than three, consider using switch instead of if-else. This not only improves the readability of the code, but also reduces the cost of understanding the code.
There are other strategies for optimizing if statements: return early; Use ternary operators; Borrow ES6 Map structure for optimization, etc. Interested students can read this article: juejin.cn/post/684490…
- Avoid creating functions in loops
Creating a function each time through a loop is not a good idea. Creating a function means memory allocation and consumption, which is useless.
- Always use === and! == perform equality judgment
= = and! The = operator can cause JS data types to be converted implicitly, with unexpected negative effects, so it is wiser to always use === and! == perform equality judgment.
- Create a new object using a literal
Using the new operator to create an object is similar to a function call. At the same time, it will do some operations such as associating the prototype chain. The performance is much slower, while the literal is more intuitive, friendly and efficient in writing.
Creating an array is similar.
- Do not omit the curly braces
Many students like to omit the curly braces after the conditional statement, as follows:
if (somethingIsTrue)
a = 100
doSomething()
Copy the code
With code like this, your goal might look something like this:
if (somethingIsTrue) {
a = 100
doSomething()
}
Copy the code
But it actually works like this:
if (somethingIsTrue) {
a = 100
}
doSomething()
Copy the code
So, put curly braces to avoid the above situation.
- Do you want a semicolon
In recent years, there has been a heated debate in JS about whether to add semicolons or not. If you know how JS is interpreted, you can choose not to add semicolons, but if you just want to save a few characters, I think it’s better to add semicolons.
Note: there are several characters that cause JS context parsing errors: parentheses, square brackets, regular leading slashes, plus, minus.
Another standard of reference is that it is only a matter of style and should be based on the style of your project. It is best to be consistent with the team. Also, mature JS compilers will decide where to add semicolons, so the probability of not adding semicolons is extremely low, and if you can use better line breaking strategies, it is perfectly fine.
- Native methods are preferred
While libraries such as LoDash and jQuery have greatly improved the productivity of JS developers, using native JS generally results in faster parsing of functionality that native JS can achieve.
Take this example:
$('input').on('focus'.function() {
if ($(this).val() === 'some text') {... }})Copy the code
Obviously, there is no need to use the val() method here, we can use the native method instead:
$('input').on('focus'.function() {
if (this.value === 'some text') {... }})Copy the code
DOM manipulation optimization
This is because the ECMAScript interpretation engine and DOM rendering engine are implemented in two parts in the browser. For example, Chrome’s JS engine is V8 and DOM is WebCore implementation. DOM operation, you can understand as cross-module operation, JS and DOM are compared to two islands, and DOM operation, JS across the bridge, to the DOM island, each operation, have to cross a bridge, frequent crossing the bridge, will cause huge performance loss (refer to the end of the “naturally slow DOM optimization”? ).
This bridge crossing process mainly occurs in the following operations:
- Access and modify DOM elements
- Reflow or Repaint DOM elements
This is one of the reasons why modern frameworks use the Virtual DOM. Without the use of modern JS frameworks, DOM manipulation is optimized by minimizing the number of bridge crossings, i.e. access to DOM elements as little as possible, and minimizing Reflows or Repaints of DOM structures.
Common optimization strategies are as follows:
- Minimize DOM access times
- Merge multiple DOM operations and insert the page once
When you need to perform a series of operations on document elements, detach the elements from the document, and then insert them into the document (this is often done using a DocumentFragment).
- Cache frequently accessed DOM elements using local variables
- Instead of iterating through a collection of HTML elements, execute after converting them to an array
The set of HTML elements is associated with the underlying document element, and each operation on the HTML element causes the set of elements to be updated.
- Use faster apis
Get elements using querySelectorAll() and querySelector() in preference. The list of nodes returned by these two methods does not correspond to a real-time document structure, thus avoiding the performance problem mentioned in the previous article.
- The animation element that causes the rearrangement is removed from the document stream
The rearrangement caused by the animation operation is likely to affect the entire document flow and cause the page to stall. Therefore, the element of such animation can be removed from the document flow using positioning, and start the BFC. After the animation is completed, the normal positioning can be returned.
Using event Delegate
Imagine a scenario where a UL has a large number of Li elements and you need to bind click events for all li elements. The most intuitive way to bind is to loop for each li:
for (let i = 0; i < uls.length; i++) {
uls[i].onClick = function() {
// do something...}}Copy the code
This circular writing method increases memory overhead on the one hand, and on the other hand, increases the cycle time per click, which degrades page performance. The solution to this situation is to use event delegates.
As the name implies, event delegation is the act of delegating the response to an event to another element, usually a parent element or a superelement. Event delegate makes use of the TIME bubble mechanism of JS. The events of the sub-layer will bubble to the outer layer. Therefore, both the parent element of the event occurrence element and the outer element can listen to the occurrence of the event. We can do this simply by using addEventListener:
uls.addEventListener('click'.function(e) {
if (e.target.tagName.toLowerCase() === 'li') {
// do something}})Copy the code
The nice thing about event delegate is that dynamically added elements can respond to.
Write more elegant JS code
A big part of a programmer’s job is not just to think about the interpreter, but to think about the people you work with, and it’s important to keep your code readable, clean, and elegant, while focusing on accurate and efficient business logic.
Clean and elegant, as I understand it, means that people reading your code can easily understand your logic without relying on comments. Similar to writing, the first priority is to communicate information accurately and concisely. Or, to borrow a saying on the web, elegant code is self-explanatory. If your code gets picked up later and you’re confused and skeptical, that’s a problem. Here are some tips for writing elegant JS code:
- Use meaningful variable names
This is a point that will be repeated again and again in any book on how to write good code, but it can’t be stressed enough. The basics are often the most important. Good variable names can greatly improve the readability of code without the need to iterate through context logic. According to the Code Book, good variable names have the following characteristics:
First of all, they’re easy to understand and good names should be as clear as possible. Good names usually say “what,” not “how.”
As for how to do this, my advice is to open up your project, look at the variable names you wrote down, think about any optimizations, or, in other words, your own code, can you know exactly what the variable in front of you represents? If not, it’s not a good name.
- Use positive judgment methods
It may be confusing at first glance to use the negative method to make a judgment condition. For example, isNumNotValid, when combined with conditional control statements, will greatly increase the reading burden:
if(! isNumNotValid) { ... }Copy the code
Plus! If num is valid or not valid, use isNumValid:
if (isNumValid) { ... }
Copy the code
- Avoid redundant code
Your code workspace is like a campsite, and you shouldn’t leave a lot of garbage behind when you leave. Redundant code refers to repeated code and code that is not executed, such as code written after a return statement, and some “temporary” trick or test code, which greatly interferes with the readability of the code.
Therefore, code writers should always read their own code to see what code is redundant, remove it as soon as possible, and adopt strategies to optimize duplicate code, such as class stripping, component stripping, modularity, variable caching, using ternary operators instead of conditional statements, and so on.
- What are the characteristics of a good function
In JS, functions are called first-class citizens, visible its importance, write a good function, for your code clean and readable is extremely important, so what are the characteristics of a good function?
- Keep it short.
A function that takes hundreds of lines is a nightmare for subsequent developers. Long functions mean complex logic or too much work to do, and should be optimized to separate such functions.
- A function should only do one thing.
If a function does too many things, it will definitely get longer and its logic will get too complicated to control.
- As few parameters as possible.
Too many arguments also means that a function is doing too many things, so in general, a function should have no more than three arguments.
- Follow the team’s style guide
Most development teams have their own development guidelines. For example, well-known companies such as Google and AirBnb have their own JavaScript guidelines. Each team should develop its own code style guidelines, which generally include code styles and some best practice strategies. Only in this way can we build a team with super combat effectiveness.
summary
This article mainly from the code level put forward some JavaScript should pay attention to the optimization writing method, for developers, we are often project-oriented programming, so, it requires us to go deep into the code at the same time, but also to learn to jump out, from the level of engineering to consider, modern popular JS framework, It is from the perspective of the overall architecture to optimize the whole JS project writing, in learning these frameworks, we should go to consider the JS bottom things, they in the end to solve what problems? Many of these issues are related to performance and best practices, and are key to moving from simple programmers to engineers.
The resources
- Hypercritical in pursuit of elegant high-performance JavaScript
- How can the INHERENTLY slow DOM be optimized?
- 【 Book 】 High Performance JavaScript