Writing javascript events with high performance and efficiency
How to make efficient web Front-end programs is a problem that I will not consciously consider every time I do front-end development. A few years ago, Yahoo's awesome front-end engineers published a book about improving the web Front-end performance, which caused a sensation in the entire web development technology field, turning the mysterious web front-end optimization problem into a cabbage, web Front-end optimization becomes a simple question that cainiao and Daniel can answer. When the industry knows the answer, the existing optimization technology can no longer overhead the quality of your website. In order to make our website develop better performance than other websites, we need to think deeply and independently, reserve better skills.
The Event System in Javascript is the first breakthrough point I have come up. Why is it a javascript Event System? We all know that the web Front-end contains three technologies: html, css, and javascript. it is clear how html and css are combined: style, class, id, and html Tag, but how can javascript be integrated into html and css? Finally, I found that the starting point is the javascript Event System. No matter how complicated javascript code we write, the event system is finally reflected in html and css, therefore, I am thinking that since the event system is the integration of the three, there will inevitably be a large number of event operations on a page, especially on today's increasingly complex web pages, without these events, the javascript code we have carefully compiled is only a warehouse, and the hero is useless. Since there will be a large number of event functions on the page, will there be problems affecting efficiency when we write event functions as we are used? The answer I have studied is true efficiency, and it is still a serious efficiency problem.
To clarify my answer, I need to explain in detail the javascript Event System.
The Event System is the starting point for integrating javascript, html, and css. This cutting point is like the main function in java. Everything magic starts from here. How does the browser complete this cutting? There are three methods I have studied:
Method 1: html event processing
Html event processing is to write the event functions directly in the html Tag. Because this write method is tightly coupled with the html tag, it is called html event processing. For example, the following code:
Copy codeThe Code is as follows:
<Input type = "button" id = "btn" name = "btn" onclick = "alert ('click Me! ') "/>
If the click Event function is complicated, it is inconvenient to write the code. Therefore, we often write the function outside, and onclick calls the function name directly, for example:
Copy codeThe Code is as follows:
<Input type = "button" id = "btn" name = "btn" onclick = "btnClk ()"/>
Function btnClk (){
Alert ("click me! ");
}
The above is a very beautiful way of writing, so many people may unconsciously use it, but maybe many people do not know, the latter is actually not as robust as the previous one, this is also a problem I recently encountered when studying the non-blocking loading script technology, because according to the frontend optimization principle, javascript code is usually located at the bottom of the page, when the page is blocked by the script, the referenced function in the html Tag may not be executed yet. At this time, we click the page button and the result will return "XXX function undefined error ", in javascript, such errors are captured by try and catch. To make the code more robust, We will rewrite it as follows:
Copy codeThe Code is as follows:
<Input type = "button" id = "btn" name = "btn" onclick = "try {btnClk ();} catch (e) {}"/>
Seeing the code above is a disgusting description.
Method 2: DOM0-level event processing
DOM0-level event processing is supported by all browsers today, and there is no compatibility problem. seeing such a sentence will make everyone who is working on the web Front-end very excited. The rule for DOM0 event processing is that each DOM element has its own event processing attribute, which can be assigned a function, such as the following code:
Copy codeThe Code is as follows:
Var btnDOM = document. getElementById ("btn ");
BtnDOM. onclick = function (){
Alert ("click me! ");
}
DOM0-level event processing uses the "on + event name" method to define the event attributes. The entire attribute is a lowercase letter. We know that DOM elements are a javascript Object in javascript code, so it is very easy to understand DOM0-level event processing from the javascript Object perspective. For example, the following code:
Copy codeThe Code is as follows:
BtnDOM. onclick = null;
The button clicking event is canceled.
Let's look at the following code:
Copy codeThe Code is as follows:
BtnDOM. onclick = function (){
Alert ("click me! ");
}
BtnDOM. onclick = function (){
Alert ("click me1111! ");
}
The next function overwrites the first function.
Method 3: DOM2 event processing and IE event processing
DOM2 event processing is a standardized event processing solution, but IE has a set of functions similar to DOM2 event processing, but the code is not quite the same.
Before proceeding to method 3, I must add some concepts. Otherwise, I cannot clarify the meaning of method 3.
The first concept is: event stream
In page development, we often encounter this situation. The work interval of a page can be represented by document in javascript. A div and div in the page are overwritten on the document element, there is a button element in the div, and the button element is overwritten on the div, which is also the document, so the problem arises. When we click this button, this click action not only happens on the button, but also the div and document actions on the click operation. The three elements of logic can be used to send click events, event streams describe the concept of the preceding scenario. Event streams mean the order in which events are received from pages.
Concept 2: Event bubbling and event capture
Event bubbling is a solution proposed by Microsoft to solve event stream problems, while event capture is an event stream solution proposed by Netscape. Their principles are as follows:
The bubble event starts with the div, followed by the body, followed by the document, and the event capture is the inverted document, followed by the body, and finally the target element div. In contrast, microsoft's solutions are more user-friendly and conform to people's operating habits. The Netscape solution is awkward. This is the consequence of the browser war, once the network view is slow, the problem of event stream is solved at the expense of user habits code.
Microsoft has designed a new event system in combination with the bubble event. It is often called ie event processing in the industry. The ie event processing method is shown in the following code:
Copy codeThe Code is as follows:
Var btnDOM = document. getElementById ("btn ");
BtnDOM. attachEvent ("onclick", function (){
Alert ("Click Me! ");
});
In ie, you can use the attachEvent method of the DOM element to add events. Compared with DOM0 event processing, the method for adding events is changed from attribute to method. Therefore, you need to pass parameters to the method when adding events, the attachEvent method receives two parameters. The first parameter is the event type. The name of the event type is the same as that of the DOM0 event processing. The second parameter is the event function, the advantage of using this method is that if we add a click event for the same element, as shown below:
Copy codeThe Code is as follows:
BtnDOM. attachEvent ("onclick", function (){
Alert ("Click Me! ");
});
BtnDOM. attachEvent ("onclick", function (){
Alert ("Click Me, too! ");
});
The two dialog boxes can be displayed normally, so that we can add multiple click events for the DOM element. What if we don't want an event? How can we do this? ie provides the detachEvent Method for event deletion. The parameter list is the same as that of attachEvent. If we want to delete a click event, we only need to pass the same parameters as the added event, the following code is used:
Copy codeThe Code is as follows:
BtnDOM. detachEvent ("onclick", function (){
Alert ("Click Me, too! ");
});
The Operation has serious consequences. We are confused that the second click is not deleted. What is the problem? As I mentioned earlier, the same parameters must be input to delete events. However, in javascript anonymous functions, javascript uses different variable storage internally even if the code of the two anonymous functions is the same, the result is that the click event cannot be deleted, so we need to write the code as follows:
Copy codeThe Code is as follows:
Var ftn = function (){
Alert ("Click Me, too! ");
};
BtnDOM. attachEvent ("onclick", ftn );
BtnDOM. detachEvent ("onclick", ftn );
In this way, the added and deleted Methods point to the same object, so the event is successfully deleted. The scenario here tells us that writing events requires a good habit that the operation functions should be defined independently, rather than using anonymous functions.
The following figure shows how the DOM2 event is handled:
DOM2 is a standardized event. When a DOM2 event is used, the event is first transmitted from the capture method to the document, and then to the body. div is a mediation point, when the event arrives at the mediation point, the event is in the target stage. After the event enters the target stage, the event starts to bubble processing, and the event ends on the document. (The starting point of the capture event and the end point of the bubble event. I will point to document in this article. The actual situation is that some browsers will capture the event from the window, and the window ends the bubble, however, I think that no matter how the browser sets it during development, we pay more attention to document, so I will use document here ). People are used to classify the target stage as a bubble, mainly because the bubble events in development are more widely used.
DOM2 event processing is very difficult. Every time an event is pushed, all elements will be traversed twice. This is worse than the ie event. ie only has bubbles, So ie only needs to traverse once, however, missing traversal does not mean that the ie event system is more efficient. Supporting both event systems from the development and design perspective will bring us greater flexibility for development, from this perspective, the DOM2 event is very useful. The DOM2 Event code is as follows:
Copy codeThe Code is as follows:
Var btnDOM = document. getElementById ("btn ");
BtnDOM. addEventListener ("click", function (){
Alert ("Click Me! ");
}, False );
Var ftn = function (){
Alert ("Click Me, too! ");
};
BtnDOM. addEventListener ("click", ftn, false );
The add event in DOM2 event processing uses addEventListener, which receives one more parameter than the ie event processing parameter. The first two parameters are the same as the two parameters in the ie event processing method, the only difference is that the on prefix must be removed from the first parameter, and the third parameter is a Boolean value. If the value is true, the event will be captured, when the value is false, the event is processed according to the bubble. The third parameter is used to understand why the event element should be run twice in DOM2 event processing, in order to be compatible with the two event models, however, please note that, whether we choose capture or bubble, the traversal is always done twice. If we choose an event processing method, in another event processing process, no event processing function will be promoted, which is the same as idling in a vehicle. With the design of the DOM2 event method, we know that DOM2 events can only execute one of the two event processing methods at runtime, and it is impossible for the two event stream systems to simultaneously promote the development, therefore, although the elements are traversed twice, the event function cannot be pushed twice. Note that I do not mean to trigger the event function twice, we can simulate the simultaneous execution of two event stream models, for example, the following code:
Copy codeThe Code is as follows:
BtnDOM. addEventListener ("click", ftn, true );
BtnDOM. addEventListener ("click", ftn, false );
However, this method uses multi-event processing, which is equivalent to two clicks.
DOM2 also provides a function to delete events. This function is removeEventListener, which is written as follows:
Copy codeThe Code is as follows:
BtnDOM. removeEventListener ("click", ftn, false );
The same as the ie event, that is, the parameter must be consistent with the parameter for defining the event. However, when removeEventListener is used, the third parameter is not passed. By default, the bubble event is deleted, because the third parameter is false by default, for example:
Copy codeThe Code is as follows:
BtnDOM. addEventListener ("click", ftn, true );
BtnDOM. removeEventListener ("click", ftn );
When running, the event is not deleted successfully.
Finally, I want to say that DOM2 event processing has been well supported in ie9 and ie9 and earlier versions, while ie8 and earlier versions do not support DOM2 events.
The following is a comparison of the three event methods:
Comparison 1: Comparison between one method and the other two methods
Method 1 is written in combination with html and javascript. You have one of them. To deepen this method, you can use html and javascript For hybrid development. To use a software term, you can use code coupling, code Coupling is not good, and it is very bad. This is the level of cainiao programmers, so one method is defeated, and the other two methods are defeated.
Comparison 2: method 2 and method 3
The two methods are similar. Sometimes it is hard to say who is good or who is bad. Looking at the above content, we find that the biggest difference between method 2 and method 3 is: method 2: one DOM element, one event, and only one event. Method 3 provides multiple event processing functions for a DOM element event. In DOM2 event processing, method 3 also allows us to precisely control the event stream. Therefore, method 3 is more powerful than method 2, so method 3 is better than method 3.
The following is the focus of this article: To solve the performance problem of the Event System, we must find a focus. Here, I will focus on the performance problem of the Event System from two points: reduce traversal times and memory consumption.
The first is the number of traversal times. Whether it is capture event streams or bubble event streams, elements are traversed. Instead, elements are traversed starting from the top window or document. If the page DOM element has a deep parent-child relationship, the more elements traverse, such as DOM2 event processing, the greater the damage of traversal. How can we solve the problem of event stream traversal? My answer is no. Some of my friends may have questions. Why? In the event system, there is an event object, which has a method to prevent bubbling or capture events. How can I say no? This friend's question makes sense, but if we want to use this method to reduce traversal, our code should deal with the relationship between the parent and child elements. If there are many page elements nested, this is a task that cannot be completed, so my answer is that the traversal problem cannot be changed, and I can only adapt to it.
It seems that reducing traversal will not solve the performance problem of the Event System, so now we only need to consider the memory consumption. I often hear people say that C # is very useful, and it is better for web Front-end development. We can drag a button directly to the page in C # IDE, when the button arrives at the page, javascript code automatically adds an event to the button. Of course, the event function is an empty function, so I think we can place 100 buttons on the page in this way, if no code works, there will be 100 button events for processing, which is super convenient. Finally, we add a specific button event to one of the buttons to let the page run, is this page highly efficient? In javascript, every function is an object, and every object consumes memory. Therefore, this useless 99 event Function Code certainly consumes a lot of valuable browser memory. Of course, we won't do this in the real development environment, but in today's era of ajax popularity and the popularity of single-page development, there are so many events on a single web page, this means that each event has an event function, but each operation will trigger only one event. At this time, all other events are lying down and sleeping, it does not play any role, but also consumes computer memory.
We need a solution to change this situation, which is true in reality. In order to clearly describe this scheme, I need to add some background knowledge first. In the DOM2 event processing, I mentioned the concept of the target object and put aside the DOM2 event processing method, the concept of the target object also exists in capture event processing and bubble event processing. The target object is the DOM element of the specific event operation. For example, if you click a button in the operation, the target object is the target object, no matter which event processing method, the event function will contain an event object. The event object has a property target, which always points to the target object, and the event object has a property currentTarget, this attribute points to the DOM elements that capture or bubble events flow. As described above, event streams flow to the document, whether it is capture events or bubble events. If we add click events to the document, the buttons on the page do not add click events, at this time, we click the button and we know that the clicking event on the document will be promoted. Here, the details are that when the clicking event in the document is promoted, the target of the event points to the button instead of the document, then we can write the code like this:
Copy codeThe Code is as follows:
<Input type = "button" id = "btn" name = "btn" value = "BUTTON"/>
<A href = "#" id = "aa"> aa </a>
Document. addEventListener ("click", function (evt ){
Var target = evt.tar get;
Switch (target. id ){
Case "btn ":
Alert ("button ");
Break;
Case "aa ":
Alert ("");
Break;
}
}, False );
Running, we find that the effect is the same as the button event we write separately. But its advantage is self-evident. A function handles the event functions of the entire page, and no event functions are idle, Which is perfect. This solution also has a professional name: event Delegate. JQuery's delegate method is based on this principle. In fact, the efficiency of event delegation is not only reflected in the reduction of event functions, but also the reduction of dom traversal operations. For example, in the above example, we add a function on document, and document is the top-level object on the page, reading it is very efficient. When we get to the specific object event, we do not use dom operations but use the target attribute of the event object. All these can be summarized in one sentence: It is really fast, fast with no reason.
Event delegation can also bring us a great by-product. Friends who have used jQuery should use the live method. The live method features that you can add event operations to page elements, even if this element does not exist on the page, you can add its events and understand the event Delegate mechanism. The live principle is quite understandable, in fact, jQuery live is implemented through event delegation, and live is also an efficient way to add events.
After understanding the event Delegate, we will find that jQuery's bind method is an inefficient method, because it uses the original event definition method, so we should use bind with caution, in fact, jQuery developers have also noticed this problem. The new version of jQuery contains an on method. The on method contains all the functions of the bind, live, and delegate methods, therefore, I suggest that my friends who read this article discard the previous method of adding events and use the on function to add events.
Event delegation has another benefit. In the preceding example, I add an event to the document. Here I want to make a comparison, in jQuery, we are used to putting the definition of DOM element events in the ready method, as shown below:
Copy codeThe Code is as follows:
$ (Document). ready (function (){
XXX. bind ("click", function (){});
});
The ready function is executed after the page DOM file is loaded. It is executed before the onload function. This provides many advantages in advance, and one of the advantages is performance improvement, the event definition like jQuery is also a standard practice. I believe some Friends bound some events outside ready and finally found that the button will be invalid. This ineffective scenario sometimes takes a moment and will be fine in a short time, therefore, we often ignore the principle of this problem. We do not bind events to the ready function. This operation is actually binding events before the DOM is loaded. During this time period, it is very likely that some elements have not been properly constructed on the page, so event binding will be invalid. Therefore, the ready defines the event to ensure that the DOM element events are defined after all the elements on the page are loaded, however, when using event delegation, you can avoid problems. For example, binding an event to a document represents the entire page. Therefore, the loading time is the earliest, so event delegation is implemented on the document, in this case, it is difficult for the browser to report the problem of "XXX function undefined. To sum up this feature, the event delegated code can run at any stage of page loading. This gives developers more freedom to improve the web page performance or enhance the web page effect.
Now, this article is complete. Good night.