【问题标题】:sleep() in Javascript [duplicate]Javascript中的sleep() [重复]
【发布时间】:2011-03-09 09:13:36
【问题描述】:

假设由于某种奇怪的原因我想阻止 Javascript 执行一段时间,我该怎么做。 JS 中没有 sleep()。请不要说做一个 while() 循环,因为那很糟糕。我可以做一个 window.showModalDialog 并将一个 window.close 放在模态对话框中,setTimeout 的时间非常短,这样用户就不会注意到对话框。这就像一小段时间的睡眠,如果需要,我可以多次调用它。还有其他方法吗?

详细地说,我的用例是 HTML5 SQL 数据库提供了异步 api,但我想将它用于存储永远不会很大的小型 web 应用程序。所以不需要异步 api,因为小型存储上的查询将在客户端运行。所以我想写一个带有sync api的ORM,这样开发者可以更方便地使用它。为了将此异步连接到同步 api,我需要睡眠之类的东西。

【问题讨论】:

  • 你能稍微解释一下你的例子吗?听起来setInterval() 是您所追求的,但我对您的用例并不是 100% 清楚。

标签: javascript html modal-dialog blocking


【解决方案1】:

我知道这个问题有点老了,但我有一个类似的问题,我需要模拟一个需要很长时间才能加载到页面上的脚本。我最终通过创建一个服务器端端点解决了这个问题,该端点在发送响应之前等待了 5 秒,然后向 DOM 添加了一个脚本标记以指向它。

虽然它需要服务器端实现,但它允许您在任何特定点停止页面。正如其他人之前所说,这将阻止整个浏览器,而不仅仅是您的脚本。

【讨论】:

    【解决方案2】:

    window.setTimeoutwindow.setInterval 几乎是你唯一的朋友。

    如何使用setTimeout递归调用设置另一个超时的函数的示例如下

    function go() {
        if (go.count < 4) {
            // logs 1, 2, 3 to firebug console at 1 second intervals
            console.log(go.count++);
            window.setTimeout(go, 1000);
        }
    }
    go.count = 1;
    
    go();
    

    如果您需要在超时完成之前清除超时,您可以选择捕获 timeoutID 以与window.clearTimeout 一起使用。

    请注意,window.setTimeoutwindow.setInterval 都不会阻止其他脚本的执行——我不相信在当前的 JavaScript 伪装下这是可能的。有一些方法可以通过编码来模拟 UI 阻塞,例如使用 showModalDialog 或使用一些全局的 blocking 布尔值,我担心这些值尽可能接近。

    【讨论】:

    • 这已经是问题了:)
    • -1:已经在问题中了。谁赞成这个?
    • 是的,它在问题中,但它几乎是 Thread.Sleep()/Insert language equivalent 的 JavaScript 答案。
    • 我投了赞成票。仅仅因为它在问题中并不意味着它不是答案。这个答案说“几乎是你唯一的朋友”,它提供了更多关于可以使用什么的数据并引入了一个新功能。
    • @nomind 它在 Javascript 中实现它的方式,因为 Javascript 都是关于回调和传递函数的。 “阻塞”不是您在 Javascript 中的操作方式,因为它会阻塞整个浏览器,而不仅仅是您的脚本。采用语言的开发技术,不要把语言挤成你所知道的。 Javascript不是一种程序语言。
    【解决方案3】:

    我可以做一个 window.showModalDialog 并将一个 window.close 放在模态对话框中,setTimeout 的时间非常短

    这是有创意的,但它只允许用户与模式对话框中的任何内容进行交互,只要它打开的时间长度。浏览器的其余部分仍然挂起,就像您刚刚调用了一个残酷的 while (new Date().getTime()&lt;t1); 循环一样。

    模态对话框对 CPU 周期更友好,并且将避免在等待较长时间的情况下触发脚本执行时间看门狗,但您必须平衡它与令人分心的闪烁打开对话框的烦恼,以及非通用浏览器支持,以及每个人都讨厌模态对话框的问题!

    这就像睡眠一小段时间,如果需要我可以多次调用它。还有其他方法吗?

    你实际上想通过睡觉来达到什么目的?如果不返回事件循环或触发模式对话框,您将不会获得任何屏幕更新或用户交互,因此我看不到内联睡眠将为您做什么。你当然不能用这种方式制作动画。

    在 Firefox 中,您将获得 Python 样式的 generators,这将允许您使用 yield 编写程序样式的交互过程,以便在必要时将控制权返回给浏览器。这可以提高代码的简单性,因为您不必将条件和循环结构重写为变量中的记忆状态。但是,由于只有 Mozilla 浏览器支持它,因此在可预见的未来您无法真正在野外使用它。

    预计到达时间:

    我想写一个带有同步 api 的 ORM,以便开发人员可以更轻松地使用它。为了将此异步连接到同步 api,我需要睡眠之类的东西。

    抱歉,一般情况下无法完成。基本 JavaScript 没有线程、协同例程或其他可以桥接同步和异步代码的原语。

    Web SQL 数据库规范依赖于浏览器调用您的结果处理函数(传递给executeSql())作为浏览器回调。浏览器回调只能在控制权传回浏览器时触发,而不是在同步执行线程内触发。

    理论上,您可以打开一个modalDialog,在modalDialog 的窗口内部执行异步Web SQL 数据库调用,然后让modalDialog 将结果返回给调用者窗口脚本中的同步代码.不过目前还没有浏览器同时支持openDatabaseopenModalDialog!

    【讨论】:

    • 查看更新问题中的用例,如果有必要的话。但是我的 showModalDialog 方法存在一些问题,例如即使我在 10 毫秒内关闭它,它也可能会出现在慢速机器上(这可能吗?)并且焦点不会回到父窗口中的正确位置。
    • @nomind:添加了无用的信息。如果未来的浏览器同时实现模态对话和 SQL 可能是可行的,但除了闪烁窗口的问题外,它还需要用户禁用他们的弹出窗口阻止程序。我认为您将不得不忍受异步代码和回调函数。或者只是使用更广泛支持的同步localStorage 后端而不是异国情调的openDatabase:对于具有对象式访问的“小型 Web 应用”,关系数据库的特性对您根本没有帮助。
    • 我不同意。任何基于 webkit 的浏览器,如 google chrome,都有 showModalDialog 和 openDatabase
    【解决方案4】:

    澄清一下:问题是在一定时间内完全停止脚本执行,而不是延迟某些代码的执行,这将是 setTimeout 或 setInterval 的任务。

    干净的 sleep() 实现在 JavaScript 中是不可能的,也是不可取的。

    setTimout 和 setInterval 不会像这里的某些人认为的那样停止脚本执行。只是注册一个函数被推迟运行。在超时/间隔等待期间,脚本的其余部分将继续运行。

    由于 JavaScript 的异步特性,“阻止”任何代码执行的唯一方法是运行给定时间的非常丑陋且绝对不推荐的 while 循环。 由于 JavaScript 本身在一个线程中运行(我们在这里不是在谈论 WebWorkers API ...)。这将阻止任何 JS 代码运行,直到该循环完成。但那真的很糟糕的风格......

    如果你的程序没有像 sleep() 这样的东西就不能工作,也许你应该重新考虑你的方法。

    【讨论】:

      【解决方案5】:

      这个答案可能有点烦人,但很简单:-)。

      由于 javascript 通常在浏览器中运行,浏览器是多线程的,其中 javascript 可能占用多个线程,因此没有像在单线程程序中那样“全局休眠”的概念。

      如果您想以任何合理的方式暂停操作,您可能需要考虑以下事项。

      假设你想要以下

      function foo(s) {
          var j = 1; var k = 1;
          sleep(s); // This would be nice right?  
          window.alert("Sum is : " + (j+k));
      }
      

      其实变成了:

      function foo(s) {
           var j = 1 ; var k = 1;
           setTimeout(s, function() { 
                  window.alert("Sum is : " + (j+k));
           });
      }
      

      当然,问题是在程序上你可能想要类似的东西

      function foo() {
         do stuff;
         pause();
         do more stuff;
         return;
      }
      
      function bar() {
            foo(10);
            window.alert("I want this to happen only after foo()");
      }
      

      问题是使用 setTimeout 并不能真正做到这一点,如上所示

      但是您可以执行以下操作:

       function foo(s, afterwards, afterparms) {
           var j = 1 ; var k = 1;
           setTimeout(s, function() { 
                  window.alert("Sum is : " + (j+k));
                  afterparms.parm1 = afterparms.parm1.toUpperCase();
                  afterwards(afterparms);
           });
       }
      
       function bar() {
            foo(10, function() {
                window.alert("This will happen after window.alert");
            }, { parm1: 'hello', parm2: 'world' } );
       }
      

      请注意,以上只是将信息传递给函数的一种方法,如果您查找函数调用约定、变量参数等,您可以做一些非常酷的事情

      如果您按程序思考,这对编程来说很烦人。但是,关于 javascript,有两件事要记住。它不是过程语言,也不是面向对象的语言。 Javascript 是一种具有复杂事件管理模型的函数式语言。所以你必须从这些方面考虑。

      这也是有道理的,因为典型的 javascript 机器是一个 gui(网络浏览器),它在设计时不想在尝试处理某些东西时完全阻塞。想象一下,当页面正在执行某项操作时,您的浏览器完全锁定,您想要扼杀对您执行此操作的程序员。

      Javascript 代码应该具有“即发即弃”的性质,如果事情必须等待事件发生才能继续,那么您应该查看 javascript 事件模型。

      虽然当您想要做一些琐碎的事情时,这不方便编程,但您可能会使用暂停等待的方式可能会遇到竞争条件,并且有一种更合适的方式来处理“您试图达到的效果”。

      如果您发布您的特殊案例,可能会有更多关于如何解决这种情况的信息。

      干杯,

      【讨论】:

      • 错了。 JS 不运行多线程。 setTimeout 也没有做问题所要求的。详情见我的回答。
      • JavaScript 是单线程的。许多浏览器也是如此。
      • 感谢您的所有 cmets。我已经用我的用例更新了这个问题,如果这证明需要 sleep() 是合理的。
      • 我不同意您的评论,即 JavaScript 既不是面向对象也不是过程式的 - 请参阅 stackoverflow.com/questions/107464/…。您的意思是它没有基于类的实现继承吗?
      【解决方案6】:

      @Russ Cam 是正确的,setTimeout 是您要找的。但是,您在问题中提到它的方式让我认为它的使用方式可能有些混乱。

      它不会阻止它所在的块的执行,而是在一定的时间间隔后调用它的输入函数。举例说明:

      function illustration() {
        // start out doing some setup code
        alert("This part will run first");
      
        // set up some code to be executed later, in 5 seconds (5000 milliseconds):
        setTimeout(function () {
          alert("This code will run last, after a 5 second delay")
        }, 5000);
      
        // This code will run after the timeout is set, but before its supplied function runs:
        alert("This will be the second of 3 alert messages to display");
      }
      

      运行此函数时,您将看到三条警报消息,在第二条和第三条之间有延迟:

      1. “这部分将首先运行”
      2. “这将是要显示的 3 条警报消息中的第二条”
      3. “此代码将在 5 秒延迟后最后运行”

      【讨论】:

      • 是的,我明白,但我想阻止执行,所以 setTimeout 无济于事。
      • 如果你想阻止执行,那么while就是你想要的,但这会冻结浏览器(因为它正在阻止执行)。我怀疑你真的想阻止执行。
      猜你喜欢
      • 1970-01-01
      • 2015-08-09
      • 2012-10-20
      • 1970-01-01
      相关资源
      最近更新 更多