Joe.wang
Joe.wang

Reputation: 11791

Mouseenter and mouseleave race issue

All, I know javascript runs in the single-thread mode. But I am not sure if there is the race issue which is common in multiple thread world in some situation. Say you have html structure

<div id='parent' class="parent container">
    <div id="child1" class="child container">
       <div id="child11" class="child container">
           <!--maybe there are more nested divs with class 'container' -->
       </div>
       <div id="child12" class="child container">
           <!--maybe there are more nested divs with class 'container' -->
       </div> 
    </div>
    <div id="child2" class="child container">
       <div id="child21" class="child container">
           <!--maybe there are more nested divs with class 'container' -->
       </div>
       <div id="child122" class="child container">
           <!--maybe there are more nested divs with class 'container' -->
       </div> 
    </div>
</div>

JS code:

$(function() {
    $('div.container').mouseenter(function(e){
        e.stopPropagation();
        $(this).css("border","2px solid red");//set it selected state.
        $(this).append("<div class='newdiv'></div>"); 
        $(this).parents().each(function(){
            if ($(this).children(".newdiv").length>0)
            {
                $(this).children(".newdiv").remove();
                $(this).css("border","1px solid black");//set father of it not selected state
            }
        });
    }).mouseleave( function(e){
        $(".newdiv",this).remove();
        if ($(this).parent().hasClass("container") && $(".newdiv",$(this).parent()).length==0)
        {
            $(this).parent().css("border","2px solid red");//set it's parent selected state.
            $(this).parent().append("<div class='newdiv'></div>"); 
        }
        $(this).css("border","1px solid black");//set it not selected state.
    });
});

I doubted there is a race issue if I moved the mouse fast enough in and out these div. because I found sometimes the div.newdiv wasn't removed. I think I just didn't understand the running mechanism of the javascript. So I have such a question. Hope someone would like to tell me more about it to help me understand it better. thanks.

Upvotes: 2

Views: 291

Answers (2)

Mostafa Shahverdy
Mostafa Shahverdy

Reputation: 2725

I think I just didn't understand the running mechanism of the javascript. So I have such a question. Hope someone would like to tell me more about it to help me understand it better.

Javascript doesn't have multithreading features, so it is wrong to say that there might be a race issue. As you may have noticed, Javascript is an event driven language. This is a kind of architecture that has two main phases, main loop, which check if any events are triggered, and event handling body, which is run for any triggered event.

In this case, the problem is with that main loop phase. onmouseenter is a small portion of time, that is when mouse comes to the edge of the node. So, if being on the edge happens at the time of checking another event in main loop, something like your problem will happen. But using hover, this portion of time will be longer, so the probability of being checked in main loop is higher (near 100%).

Upvotes: 3

Praveen Kumar Purushothaman
Praveen Kumar Purushothaman

Reputation: 167240

Instead, I can suggest you a better solution, instead of mouseenter and mouseleave, which would be .hover() and it doesn't conflict.

$('div.container').hover(function(e){
    e.stopPropagation();
    $(this).css("border","2px solid red");//set it selected state.
    $(this).append("<div class='newdiv'></div>"); 
    $(this).parents().each(function(){
        if ($(this).children(".newdiv").length>0)
        {
            $(this).children(".newdiv").remove();
            $(this).css("border","1px solid black");//set father of it not selected state
        }
    });
}, function(e){
    $(".newdiv",this).remove();
    if ($(this).parent().hasClass("container") && $(".newdiv",$(this).parent()).length==0)
    {
        $(this).parent().css("border","2px solid red");//set it's parent selected state.
        $(this).parent().append("<div class='newdiv'></div>"); 
    }
    $(this).css("border","1px solid black");//set it not selected state.
});

Upvotes: 2

Related Questions