【问题标题】:Halt JavaScript execution without locking up the browser在不锁定浏览器的情况下停止 JavaScript 执行
【发布时间】:2010-01-19 21:48:23
【问题描述】:

您能否在不锁定浏览器的情况下停止 JavaScript 执行?通常停止执行的方法是无限循环while()-loop,但对于 FireFox,它会锁定浏览器直到循环结束。

您对此有何看法?


我正在尝试覆盖 window.confirm() 以使用 HTML 实现我自己的对话框。我这样做是为了不必更改现有代码(这是一个相当大的代码库)。

我需要能够暂停执行以允许用户输入;反过来像标准确认函数一样返回一个布尔值:

if (confirm("..."))
{
    // user pressed "OK"
}
else
{
    // user pressed "Cancel"
}



更新

据我所知;这不能使用setTimeout()setInterval() 来完成,因为这些函数异步执行给它们的代码。

【问题讨论】:

  • setTimeoutsetInterval 不要异步执行代码,它们会倒计时,然后将回调函数添加到线程空闲时调用的队列中。然后函数本身同步运行。
  • @Andy E - window.setTimeout(和window.setInterval)创建异步回调。正常程序流程在调用后立即继续,回调在稍后执行,具体取决于计时器长度。 JavaScript 是单线程的,并且回调一旦开始执行,就会阻止其他代码执行,这并不能阻止它是异步的。

标签: javascript execution


【解决方案1】:

confirm() prompt()alert() 是特殊函数——它们从 JavaScript 沙箱调用到浏览器中,浏览器暂停 JavaScript 执行。你不能做同样的事情,因为你需要将你的功能构建到 JavaScript 中。

我认为没有按照以下方式进行一些重组就可以替换的好方法:

myconfirmfunction(function() {
   /* OK callback */
}, function() {
   /* cancel callback */
});

【讨论】:

    【解决方案2】:

    要么使用回调,要么让您的代码仅用于 Firefox。在支持 JavaScript 1.7 及更高版本的 Firefox 中,您可以使用 yield 语句来模拟您想要的效果。为此,我创建了一个名为 async.js 的库。 async.js 的标准库包含一个确认方法,可以这样使用:

    if (yield to.confirm("...")) {
      // user pressed OK
    } else {
      // user pressed Cancel
    }
    

    【讨论】:

      【解决方案3】:

      您无法在 JavaScript 中停止事件线程,因此您必须解决该问题,通常使用回调函数。这些是稍后运行的函数,但可以像 JavaScript 中的任何其他对象一样传递。您可能从 AJAX 编程中熟悉它们。所以,例如:

      doSomeThing();
      var result = confirm("some importart question");
      doSomeThingElse(result);
      

      将被转换为:

      doSomeThing();
      customConfirm("some importart question", function(result){
        doSomeThingElse(result);
      });
      

      customConfirm 现在接受一个问题并将结果传递给它作为参数的函数。如果您使用按钮实现 DOM 对话框,则将事件侦听器连接到 OK 和 CANCEL 按钮,并在用户单击其中一个时调用回调函数。

      【讨论】:

        【解决方案4】:

        JavaScript 语言有一个扩展名为 StratifiedJS。它在每个浏览器中运行,它允许您这样做:停止一行 JavaScript 代码而不冻结浏览器。

        您可以启用分层 JavaScript,例如通过在您的网页中包含 Oni Apollo (http://onilabs.com/docs),例如:

        <script src="http://code.onilabs.com/latest/oni-apollo.js"></script>
        <script type="text/sjs"> your StratifiedJS code here </script>
        

        您的代码如下所示:

        var dom = require("dom");
        displayYourHtmlDialog();
        waitfor {
          dom.waitforEvent("okbutton", "click");
          // do something when the user pressed OK
        }
        or {
          dom.waitforEvent("cancelbutton", "click");
        }
        hideYourHtmlDialog();
        // go on with your application
        

        【讨论】:

          【解决方案5】:

          您通常停止执行的方式几乎不应该是无限的while循环。

          将您的工作分解为您使用 SetTimeout 调用的部分

          改变这个:

            DoSomeWork();
            Wait(1000);
            var a = DoSomeMoreWork();
            Wait(1000);
            DoEvenMoreWork(a);
          

          到这里:

           DoSomeWork();
           setTimeout(function() {
              var a = DoSomeMoreWork();
              setTimeout(function() { 
                  DoEvenMoreWork(a);
              }, 1000);
           }, 1000);
          

          【讨论】:

            【解决方案6】:

            我认为没有任何方法可以在您自己的 JavaScript 中合理地重新创建 confirm() 或 prompt() 的功能。它们在被实现为对本机浏览器库的调用的意义上是“特殊的”。你不能在 JavaScript 中真正做那种模态对话框。

            我见过各种 UI 库,它们通过在页面顶部放置一个元素来模拟效果,看起来和行为类似于模式对话框,但它们是使用异步回调实现的。

            您将不得不修改现有库,而不是替换 window.confirm。

            【讨论】:

              【解决方案7】:

              我尝试对this 使用紧密循环。我需要减慢本机事件(AFAIK 是同步等待的唯一用例,不能异步重新架构)。有很多示例循环声称不会锁定浏览器;但它们都不适合我(浏览器没有锁定,但他们阻止它做我一直在等待的事情),所以我放弃了这个想法。

              接下来我尝试了this - 存储和重放事件,这似乎也是不可能的跨浏览器。但是,根据活动和您需要的灵活性,您可以接近。

              最后我放弃了,感觉好多了;我找到了一种方法,可以让我的代码工作,而无需减慢原生事件的速度。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-01-13
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多