JS bubble and closure case analysis and js bubble Case Analysis

Source: Internet
Author: User

JS bubble and closure case analysis and js bubble Case Analysis

Background:

Today, I found Baidu aware of an interesting JS problem on the webpage. The question of the questioner is actually quite simple. I should be able to implement front-end development technology. The questioner's requirement: submenu pop-up is implemented. There are three levels of menus, with a latency of 500 ms for each menu display. Then the questioner posted his problem code.

I will take a look at the code posted by others as long as it is not particularly complicated. After all, programmers communicate with each other and the source code is the best language. At the beginning, it seems a bit wrong with his code. Later, I analyzed it carefully and found it really interesting. If you feel that the analysis process is boring, you can directly look at the conclusion.

The following is his code:

<Html> 

The above code, we take out the JS part to study:

onload = function() {var lis = document.getElementsByTagName("li");var t = 0;for (var i = 0; i < lis.length; i++) {lis[i].timer = null;lis[i].onmouseover = function() {me = this;me.timer = setInterval(function() {if (me.children[0]) {me.children[0].style.display = "block"}}, 500)}lis[i].onmouseout = function() {clearInterval(me.timer)this.children[0] ? this.children[0].style.display = "none" : 0;}}}

First, let alone the most basic errors. For example, you should use setTimeout to set the latency.

 

Problem:

I think many people should have the same question as me: After the mouse moves to the sub-menu, the onmouseout method should be executed for the first-level menu, and then the sub-menu should be hidden. However, if the mouse moves fast, the sub-menu will flash, but it will eventually be displayed, but the third-level menu will not be displayed.

 

Question:

Is the onmouseout method not executed? With this question, I added console. log to the onmouseout and onmouseover methods, and debugged the breakpoint. The result shows a meaningful phenomenon.

The onmouseout method is indeed executed, that is, the style attribute of the sub-menu is changed to none, but the console displays the execution sequence of the rectification method: parent menu onmouseout-> sub menu onmouseover-> parent menu onmouseover-> child node onmouseout-> parent node onmouseout

 

Cause:

There are three main reasons for the above problems:

(1) JS execution takes time, especially setting the display of the style will cause render Tree Reconstruction, so no changes will be found in the interface.

(2) The onmouseover function of the questioner intentionally sets a latency of 500 milliseconds to execute the display function.

(3) The event model of the browser is executed in bubble mode.

 

Analysis:

Of course, the above reason is:

When the mouse moves to the sub-menu, the Browser executes the onmouseout of the parent menu. In theory, the sub-menu needs to be hidden, but for the first reason, the sub-menu is not hidden, move the mouse to the Level 2 menu. At this time, the browser needs to trigger the onmouseover method on the second-level menu, then execute the onmouseover method of the sub-menu, and set the delay function, because we have not blocked event bubbling, the onmouseover of the level-2 menu bubbles to the level-1 menu and runs the onmouseover of the parent menu.

 

After analysis, we should note that the second-level menu should display its sub-menu (level-3 menu) in onmouseover. However, we should note that the onmouseover logic is not a normal logic, but a delay. Therefore, the show function (that is, the anonymous function) of the level-2 menu is executed after the onmouseover function of the level-1 menu, so the closure variable me is changed. After debugging, we can find that the me variable is mounted in windows, so it is a global variable. The onmouseover sub-menu sets it as the sub-node itself, but then it bubbles to the parent node, and this of onmouseover changes to the parent node itself, so the show function is executed twice, and the me variables twice are the nodes corresponding to the parent menu.

The above problem is a bit similar to the resource competition for multi-threaded programming in advanced programming languages (such as Java). In advanced programming languages, in order to synchronize a resource (variable, object ), the language itself provides keywords similar to synchronized. Of course we are not multithreading here, and we cannot synchronize this variable (the solution will be discussed later ).

 

Next, I analyzed the two onmouseout, which is actually better understood. When the program is executed here, the browser finally restructured the render Tree and the sub menu is hidden, then the browser considers that our mouse is removed from the sub-menu, so the onmouseout event of the sub-menu is started and executed in a bubble mode. The specific process is not analyzed.

After the program runs onmouseout twice, it will certainly not take 500 ms, unless your machine is very old, so at this time, the two delay functions we set will be triggered. Then execute the me sub-node display. We mentioned above that the me of the two show functions is actually the same variable and all point to the node corresponding to the parent menu. Therefore, the subnode is displayed.

Here, our problem comes again. If clearTimeout is called in onmouseout, the two delay functions should be canceled. The answer is that clearTimeout is incorrectly used. I believe that many people, like me, have never considered JS as a complete technology, so we know that setTimeout and setInterval are canceled using the corresponding clear method. But we have never studied its running mechanism (of course, it is not necessary in many cases, just like when Java came out, few people care about the JVM Layer ). Here we will not go into it, but give a conclusion that we can know from W3C. Both setTimeout and setInterval return a string (similar to Thread ID). When calling the clear method, you need to input the corresponding ID to stop the execution of the delay function.

Last question: Since the sub-menu has gone through the hidden display process, why does the browser trigger onmouseout without triggering onmouseover again to form an endless loop and let the page die? As for this question, I have not found a standard answer. Maybe the browser triggers the mouse event in pixels. We didn't move the mouse any more, and naturally it won't trigger onmouseover.

 

Conclusion:

A bunch of nonsense, many people should be impatient, let's draw a conclusion.

(1) JS programming, we must pay attention to event bubbling. Bubbling is a good thing, but we should be careful when using it. Event bubbling can improve program efficiency, such as table operations, most of the time, we will let the event bubble to the table for further operations, so that high execution efficiency. JQuery event processing makes good use of bubble.

(2) Use closures with caution. In JS programming, closures can easily cause memory leaks and be used with caution. closure variables are easily called Resource Competition objects, especially in delayed functions, it is easy to have inexplicable problems.

(3) The IDS returned by setInterval and setTimeout must be passed in clearInterval and clearTimeout. Otherwise, the delay cannot be canceled normally.

(4) onmouseenter and onmouseleave can be used as a solution to solve the above problems, but pay attention to compatibility issues! Onmouseenter and onmouseleave do not bubble events, onmouseover and onmouseout will bubble to the parent node, and this point will also change.

 

PS:

Today I spoke a bunch of nonsense. It's boring to analyze this case. "Not seeking for a thorough understanding" is certainly a philosophy of study, but "tracing the source" is the solution to the problem. It is far easier to give a correct answer to the problem.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.