![](/img/trans.png)
[英]Why calling of window.setTimeout for the same function doesn't introduce infinite loop?
[英]Why is window.setTimeout(someFunc, 0) not the same as calling someFunc directly?
我正在尝试在我的网页中使用JS实现下拉菜单。 我知道这可以用CSS,但我仍然想用JS来完成这个。
所以我在Google上搜索并找到了这段代码:
var timeout = 500;
var closetimer = 0;
var ddmenuitem = 0;
// open hidden layer
function mopen(id)
{
// cancel close timer
mcancelclosetime();
// close old layer
if(ddmenuitem) ddmenuitem.style.visibility = 'hidden';
// get new layer and show it
ddmenuitem = document.getElementById(id);
ddmenuitem.style.visibility = 'visible';
}
// close showed layer
function mclose()
{
if(ddmenuitem) ddmenuitem.style.visibility = 'hidden';
}
function mclosetime()
{
closetimer = window.setTimeout(mclose, timeout);
}
// cancel close timer
function mcancelclosetime()
{
if(closetimer)
{
window.clearTimeout(closetimer);
closetimer = null;
}
}
// close layer when click-out
document.onclick = mclose;
#sddm
{ margin: 0;
padding: 0;
z-index: 30}
#sddm li
{ margin: 0;
padding: 0;
list-style: none;
float: left;
font: bold 11px arial}
#sddm li a
{ display: block;
margin: 0 1px 0 0;
padding: 4px 10px;
width: 60px;
background: #5970B2;
color: #FFF;
text-align: center;
text-decoration: none}
#sddm li a:hover
{ background: #49A3FF}
#sddm div
{ position: absolute;
visibility: hidden;
margin: 0;
padding: 0;
background: #EAEBD8;
border: 1px solid #5970B2}
#sddm div a
{ position: relative;
display: block;
margin: 0;
padding: 5px 10px;
width: auto;
white-space: nowrap;
text-align: left;
text-decoration: none;
background: #EAEBD8;
color: #2875DE;
font: 11px arial}
#sddm div a:hover
{ background: #49A3FF;
color: #FFF}
<ul id="sddm">
<li><a href="#" onmouseover="mopen('m1')" onmouseout="mclosetime()">Home</a>
<div id="m1" onmouseover="mcancelclosetime()" onmouseout="mclosetime()">
<a href="#">HTML DropDown</a>
<a href="#">DHTML DropDown menu</a>
<a href="#">JavaScript DropDown</a>
<a href="#">DropDown Menu</a>
<a href="#">CSS DropDown</a>
</div>
</li>
<li><a href="#" onmouseover="mopen('m2')" onmouseout="mclosetime()">Download</a>
<div id="m2" onmouseover="mcancelclosetime()" onmouseout="mclosetime()">
<a href="#">ASP Dropdown</a>
<a href="#">Pulldown menu</a>
<a href="#">AJAX dropdown</a>
<a href="#">DIV dropdown</a>
</div>
</li>
<li><a href="#" onmouseover="mopen('m3')" onmouseout="mclosetime()">Order</a>
<div id="m3" onmouseover="mcancelclosetime()" onmouseout="mclosetime()">
<a href="#">Visa Credit Card</a>
<a href="#">Paypal</a>
</div>
</li>
<li><a href="#" onmouseover="mopen('m4')" onmouseout="mclosetime()">Help</a>
<div id="m4" onmouseover="mcancelclosetime()" onmouseout="mclosetime()">
<a href="#">Download Help File</a>
<a href="#">Read online</a>
</div>
</li>
<li><a href="#" onmouseover="mopen('m5')" onmouseout="mclosetime()">Contact</a>
<div id="m5" onmouseover="mcancelclosetime()" onmouseout="mclosetime()">
<a href="#">E-mail</a>
<a href="#">Submit Request Form</a>
<a href="#">Call Center</a>
</div>
</li>
</ul>
<div style="clear:both"></div>
<div style="clear:both"></div>
我编辑了一下JS,因为我希望在鼠标指针移出下拉列表后,下拉列表立即消失。 所以我改成了这个:
function mclosetime()
{
closetimer = window.setTimeout(mclose, 0);
}
并删除了timeout
变量。 一切仍然有效。 然后我意识到mclosetime
基本上调用了mclose
,延迟为0.我认为mclosetime
是一个功能不大,可以删除。 所以我删除了它并更改了li
元素直接调用mclose
:
<li><a href="#" onmouseover="mopen('m1')" onmouseout="mclose()">Home</a>
<div id="m1" onmouseover="mcancelclosetime()" onmouseout="mclose()">
<a href="#">HTML DropDown</a>
<a href="#">DHTML DropDown menu</a>
<a href="#">JavaScript DropDown</a>
<a href="#">DropDown Menu</a>
<a href="#">CSS DropDown</a>
</div>
</li>
然后下拉列表不再起作用了! 将鼠标指针移动到下拉菜单后,下拉消失。 我认为这是由于closetimer
为0引起的,所以我把mclose
更改为:
function mclose()
{
closetimer = 1;
if(ddmenuitem) ddmenuitem.style.visibility = 'hidden';
}
仍然发生同样的事情。
我真的很困惑。 如果超时为0, window.setTimeout
不会调用该函数吗? 如果它没有做到这一点, mclose
在这里调用mclose
应该可行!
setTimeout(myFun, 0)
无法保证myFun
会立即被调用。
在钩子下,当你执行window.setTimeout(myFun, 0)
,浏览器只是将函数myFun
放到浏览器事件队列中。 只有队列中没有其他内容时,浏览器才会立即执行它。 那么队列中是否存在某些内容,它将比myFun
更早执行。
setTimout
异步工作。 这意味着,一旦当前调用堆栈执行完毕,它就mclose
排队。 如果直接调用mclose
,它将按顺序(同步)在当前调用堆栈中执行,但setTimout
会在下一个调用堆栈中立即执行它。
setTimeout函数没有问题。 问题在于JavaScript的mouse-out
事件,它也会应用于嵌套的子元素。 只要将鼠标移动到子DIV,就会触发父项的鼠标输出事件。 JQuery通过使用mouseleave
事件提供了一个简单的解决方案,它完全符合您的要求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.