Javascript 匿名函数和全局变量

标签 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);

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

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

显然,不知何故,countdowntimer 有两个值 float ,但为什么呢?

编辑

好的,所以我(现在)明白 Javascript 是单线程的。那 - 有点 - 回答了我的问题。但是,在这个单线程的处理过程中,所谓的使用 setInterval 的异步调用真的发生了吗?它只是在函数调用之间吗?肯定不是,那些需要很长时间执行的函数呢?

最佳答案

周围没有变量的两个副本。 Web 浏览器中的 Javascript 单线程(除非您使用 new web workers stuff )。所以匿名函数永远没有机会运行,因为 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

编辑 回答您的后续问题:

But, at which point in the processing of this single thread, does the so called asynchronous call using setInterval actually happen? Is it just between function calls? Surely not, what about functions that take a long time to execute?

差不多,是的 - 因此函数不要长时间运行很重要。 (从技术上讲,它甚至不在函数调用之间,因为如果您有一个调用其他三个函数的函数,则解释器在该(外部)函数运行时不能做任何其他事情。)解释器本质上维护一个它需要的函数队列执行。它首先执行任何全局代码(而不是像一个大函数调用)。然后,当事情发生时(用户输入事件,调用通过 setTimeout 安排的回调的时间到了,等等),解释器将它需要进行的调用推送到队列中。它总是在队列的前面处理调用,所以事情可以堆叠起来(比如你的 setInterval 调用,虽然 setInterval 是一个特殊 - 如果前一个回调仍在队列中等待处理,它不会将后续回调排队)。因此,请考虑您的代码何时获得控制权以及何时释放控制权(例如,通过返回)。解释器只能在您释放控制权之后和再次将控制权还给您之前做其他事情。同样,在某些浏览器(例如 IE)上,同一个线程也用于绘制 UI 等,因此 DOM 插入(例如)不会显示,直到您将控制权交还给浏览器以便它可以获取继续绘画。

当在网络浏览器中使用 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);
// If we had code here, it would happen *immediately*,
// it wouldn't wait for the answer

因此,例如,askTheQuestion 可能会在页面上覆盖一个 div,其中包含提示用户输入各种信息的字段,并在用户完成后单击“确定”按钮。 setCallbackForQuestionAnswered 实际上是 Hook “确定”按钮上的 click 事件。 doSomethingWithAnswer 将从字段中收集信息,删除或隐藏 div,并对信息做一些事情。

关于Javascript 匿名函数和全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2857945/

相关文章:

javascript - 为什么 $event 不能与 ng-change 一起使用?

javascript - 如何将服务注入(inject)到类中,然后用它扩展组件?

php - PHP 中全局变量和函数参数之间的优点/缺点?

c++ - 动态链接共享库中的全局变量和静态变量会发生什么情况?

performance - 如何在不牺牲性能的情况下将函数作为参数传递给Julia中的其他函数?

javascript - 为什么复制的 HTML 看起来不像原始 HTML?

javascript - 为什么对 html 属性使用变量?

javascript - JavaScript 中的全局变量如何工作?

javascript - ExtJS - 从不同文件访问变量

c# - 递归匿名函数的 StackOverflowException