Javascript匿名函数和全局变量

Gui*_*ips 4 javascript global-variables anonymous-function setinterval

我以为我会尝试并且聪明并创建一个我自己的Wait函数(我意识到还有其他方法可以做到这一点).所以我写道:

var interval_id;
var countdowntimer = 0;

function Wait(wait_interval) {
  countdowntimer = wait_interval;

  interval_id = setInterval(function() {
    --countdowntimer <=0 ? clearInterval(interval_id) : null;
  }, 1000);

  do {} while (countdowntimer >= 0);
}

// Wait a bit: 5 secs
Wait(5);
Run Code Online (Sandbox Code Playgroud)

这一切都有效,除了无限循环.检查后,如果我取出While循环,则按预期输入匿名函数5次.很明显,全局变量countdowntimer递减了.

但是,如果我检查countdowntimer的值,在While循环中,它永远不会下降.尽管在While循环中调用了匿名函数,但这是事实!

很明显,不知何故,倒计时器有两个值浮动,但为什么呢?

编辑

好的,所以我理解(现在)Javascript是单线程的.而那 - 有点 - 回答我的问题.但是,在处理这个单线程的那一点上,使用setInterval的所谓异步调用实际上是否会发生?它只是在函数调用之间吗?当然不是,那些需要很长时间才能执行的功能呢?

T.J*_*der 5

周围没有两个变量副本.Web浏览器中的Javascript是单线程的(除非您使用新的Web工作人员的东西).因此,匿名函数永远不会有机会运行,因为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 a bit: 5 secs
Wait(5, function() {
    alert("Done waiting");
});

// Any code here happens immediately, it doesn't wait for the callback
Run Code Online (Sandbox Code Playgroud)

编辑回答您的后续行动:

但是,在处理这个单线程的那一点上,使用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();
Run Code Online (Sandbox Code Playgroud)

这在事件驱动的世界中不起作用.相反,你这样做:

askTheQuestion();
setCallbackForQuestionAnsweredEvent(doSomethingWithAnswer);
// If we had code here, it would happen *immediately*,
// it wouldn't wait for the answer
Run Code Online (Sandbox Code Playgroud)

因此,例如,askTheQuestion可以在页面上覆盖div,其中字段提示用户输入各种信息,并带有"确定"按钮,以便他们在完成后单击.setCallbackForQuestionAnswered真的会click在"确定"按钮上挂钩事件.doSomethingWithAnswer将从字段中收集信息,删除或隐藏div,并对信息执行某些操作.