变量不会存在两份。除非你使用新的Web Workers,否则Web浏览器中的Javascript是单线程的。因此,匿名函数永远没有机会运行,因为Wait
正在占用解释器。
在基于浏览器的Javascript中,不能使用忙等待函数;其他任何操作都将被阻塞(即使在大多数其他环境中,它们也是一个坏主意)。必须使用回调函数。以下是对此的最简化改写:
var interval_id;
var countdowntimer = 0;
function Wait(wait_interval, callback) {
countdowntimer = wait_interval;
interval_id = setInterval(function() {
if (--countdowntimer <=0) {
clearInterval(interval_id);
interval_id = 0;
callback();
}
}, 1000);
}
Wait(5, function() {
alert("Done waiting");
});
编辑 回答您的后续问题:
但是,在处理此单个线程的过程中,所谓的使用setInterval的异步调用在哪个时刻实际发生?仅在函数调用之间吗?当然不是,对于执行时间长的函数怎么办?
基本上是这样的,因此重要的是函数不要运行时间过长。(严格来说甚至不是在函数调用之间,因为如果您有一个调用三个其他函数的函数,则解释器在运行该(外部)函数时无法执行任何其他操作。)解释器实际上维护了一个它需要执行的函数队列。它从执行任何全局代码(很像一个大型函数调用)开始。然后,当事件发生时(用户输入事件、达到通过setTimeout
安排的回调调用的时间等),解释器将它需要进行的调用推到队列中。它总是处理队列前面的调用,因此事情可能会堆积起来(比如您的setInterval
调用,尽管setInterval
有点特殊——如果先前的回调仍在队列中等待处理,则它不会排队下一个回调)。因此,请考虑您的代码何时获取控制权以及何时释放控制权(例如,通过返回)。只有在您释放控制权并在将其再次返回给您之前,解释器才可以执行其他操作。此外,在一些浏览器上(例如IE),同一线程还用于绘制UI等方面,因此DOM插入(例如)将不会显示,直到您将控制权释放回浏览器,以便它继续进行绘制。
在Web浏览器中使用Javascript时,您确实需要采用基于事件驱动的方法来设计和编写解决方案。典型的例子是提示用户提供信息。在非事件驱动的世界中,您可以这样做:
// Non-functional non-event-driven pseudo-example
askTheQuestion();
answer = readTheAnswer(); // Script pauses here
doSomethingWithAnswer(answer); // This doesn't happen until we have an answer
doSomethingElse();
在事件驱动的世界中,这种方法行不通。相反,你需要这样做:
askTheQuestion();
setCallbackForQuestionAnsweredEvent(doSomethingWithAnswer);
因此,例如,
askTheQuestion
可能在页面上覆盖一个 div,并提示用户填写各种信息的字段,并为他们提供“确定”按钮,以便在完成后单击。
setCallbackForQuestionAnswered
实际上是钩住“确定”按钮上的
click
事件。
doSomethingWithAnswer
将收集字段中的信息,移除或隐藏 div,并对信息进行处理。