繁体   English   中英

Javascript匿名函数和全局变量

[英]Javascript Anonymous Functions and Global Variables

我以为我会尝试并且聪明并创建一个我自己的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递减了。

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

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

编辑

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

周围没有两个变量副本。 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

编辑回答您的后续行动:

但是,在处理这个单线程的那一点上,使用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);
// If we had code here, it would happen *immediately*,
// it wouldn't wait for the answer

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

大多数Javascript实现都是单线程的 ,所以当它执行while循环时,它不会让其他任何东西执行,所以在while运行interval永远不会运行,从而产生无限循环。

有许多类似的尝试在javascript中创建一个睡眠/等待/暂停功能,但由于大多数实现是单线程的,它只是不会让你在睡觉时做任何其他事情(!)。

延迟的另一种方法是写入超时 他们可以推迟执行一大块代码,但你必须在许多函数中打破它。 您始终可以内联函数,以便更容易遵循(并在同一执行上下文中共享变量)。

还有一些库为javascript添加了一些合成的糖,使其更具可读性。

编辑: John Resig自己有一篇关于javascript计时器如何工作的博客文章。 他几乎详细解释了这一点。 希望能帮助到你。

实际上,它几乎可以保证,当循环执行时,间隔函数永远不会运行,因为javascript是单线程的。

有一个原因,为什么没有人做过Wait (这么多人已经尝试过); 它根本无法完成。

您将不得不求助于将函数制成位并使用setTimeout或setInterval计划这些位。

//first part
...
setTimeout(function(){
    //next part
}, 5000/*ms*/);

根据您的需要,这可以(应该)实现为状态机。

而不是使用全局倒计时器变量,为什么不改变setInterval上的毫秒属性呢? 就像是:

var waitId;

function Wait(waitSeconds)
{
    waitId= setInterval(function(){clearInterval(waitId);}, waitSeconds * 1000);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM