JavaScript的执行流可以被中断吗? 我一直认为,由于JavaScript是单线程的,所以我可以附加事件处理程序,而不用担心在执行代码的过程中执行的处理程序。令我惊讶的是,我发现他们可以。据了解,“无响应脚本”对话框可能导致在脚本仍在运行时引发事件

JavaScript的执行流可以被中断吗? 我一直认为,由于JavaScript是单线程的,所以我可以附加事件处理程序,而不用担心在执行代码的过程中执行的处理程序。令我惊讶的是,我发现他们可以。据了解,“无响应脚本”对话框可能导致在脚本仍在运行时引发事件,javascript,javascript-events,concurrency,Javascript,Javascript Events,Concurrency,我使用以下代码对此进行了测试: <script> function loop() { var cond; onblur = function (event) { cond = false; }; cond = true; while (cond) ; alert('loop exited!'); } </script&g

我使用以下代码对此进行了测试:

<script>
    function loop() {
        var cond;
        onblur = function (event) {
            cond = false;
        };
        cond = true;
        while (cond)
            ;
        alert('loop exited!');
    }
</script>
<button onclick="loop()">loop()</button>

函数循环(){
无功状态;
onblur=函数(事件){
cond=假;
};
cond=真;
while(cond)
;
警报('循环已退出!');
}
循环()

在Firefox11.0中,函数在单击“继续”后打印“循环退出”。循环似乎已暂停,允许执行事件。这类似于临时更改目标线程上下文的。但它更危险,因为它允许改变外部状态


这是虫子吗?我是否应该不再依赖JavaScript的单一执行流模型并确保所有脚本都是可重入的?或者,尽管主流浏览器允许这种情况发生,但这是一个不值得追求的缺陷吗?

是的,如果创建一个无限循环,您将挂起JavaScript。不同的浏览器将以不同的方式处理此问题。Firefox 11 for me弹出一个窗口,显示您的脚本已挂起。Chrome目前正在为我旋转

这应该证明这一点。永远不要在FF11或Chrome 17中调用
alert()

while(true){}
alert("sucks");

您询问了JavaScript中的同步语句。还有一些其他同步语句会阻止JavaScript的执行,如
alert()
confirm()
、同步ajax调用等等


您通常希望避免JavaScript中的任何同步内容!如果您想让事情暂停,您可能需要重新思考设计。JavaScript是事件驱动的。你不需要它在一个while循环中旋转,因为页面上的任何东西都不起作用,包括任何事件,如点击等。

我认为当你开始处理事件时,问题就出现了

而不是使用while循环,考虑使用递归函数。 下面是我对您的代码所做的一些修改,这些修改应该按照需要执行

<head>
    <script>
    function loop(that) {
        var cond;
        that.onblur = function (event) {
            cond = false;
        };
        cond = true;
        var loop = 0
        var xy = function x (){
            if(cond == true){
                loop++;         
                setTimeout(function(){xy()},0);
            } else {
                alert('loop exited! - '+loop);
                return true;
            }
        }
        xy();
    }
    </script>
</head>
<body>
    <button onclick="this.focus(); loop(this)">loop()</button>
</body>

函数循环(that){
无功状态;
that.onblur=函数(事件){
cond=假;
};
cond=真;
变量循环=0
var xy=函数x(){
如果(cond==true){
loop++;
setTimeout(函数(){xy()},0);
}否则{
警报('循环已退出!-'+循环);
返回true;
}
}
xy();
}
循环()

使用延迟为0的setTimeout()应该允许任何事件在没有任何问题的情况下跳入。循环代码的执行速度不会很快,但您只需测试一下就可以了。

我想真正的问题应该是:“标准调用了什么。”我认为最好将一些内置行为(
alert()
等)发生的“暂停”视为解释器强制“屈服”的形式从当时运行的函数开始,然后在“暂停”完成后,继续执行。换句话说,当“暂停”正在进行时,将函数视为实际返回,然后继续作为继续继续继续。通过这种方式,事件处理变得更有意义,因为它就像普通的事件处理一样。获得“无响应脚本”提示几乎不是一件你应该设计的正常事情。如果用户获得其中一个对话框,则您的应用程序已损坏。您应该设计脚本,使“无响应脚本”提示永远不会出现,这样您就不必担心重新进入。在我看来,主浏览器允许在该提示符中触发事件确实是一个小错误,但我认为更重要的是修复代码,这样提示符就不会出现,也不会出现问题。@jfriend00问题不在于我的脚本运行时间太长;浏览器可以任意中断正在运行的代码并执行用户回调。当然,如果无响应的脚本行为被证明是一个bug,那么这个想法就没有依据了,但我们不知道这一点。如果您这样做,请将其作为答案提交。:)你联系到的答案很清楚,不是吗?如果有帮助,可以这样想:为了显示对话框,浏览器的事件循环需要运行。从理论上讲,窗口的消息队列可以插入脚本,而其他一切都可以插入,但这比整个浏览器UI是XUL和JS时听起来要困难。相关:现在Mozilla中至少有一种特殊情况,在同步XHR进行时插入计时器,但一般情况不太清楚。如果你需要在不阻止UI事件的情况下旋转while循环,你可以使用一个网络工作者:@Timothy003认为我应该用真实的信息替换FUD:)