在Javascript中sleep()

时间:2010-06-28 23:08:56

标签: javascript html5 modal-dialog blocking

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

详细说明,我的用例是HTML5 SQL数据库已经给出了异步api,但我想将它用于一个小商店永远不会大的小型webapp。因此不需要异步api,因为小商店上的查询将在客户端运行。所以我想编写一个带有sync api的ORM,以便开发人员可以更轻松地使用它。要将此异步桥接到同步api,我需要像睡眠这样的东西。

6 个答案:

答案 0 :(得分:14)

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();

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

请注意,window.setTimeoutwindow.setInterval都不会阻止其他脚本的执行 - 我不认为这可能是JavaScript的当前形式。有一些方法可以编码来模仿UI阻止,例如使用showModalDialog或者使用一些全局blocking布尔值,这些布尔值几乎就像我害怕的那样。

答案 1 :(得分:9)

@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秒后运行最后一次”

答案 2 :(得分:6)

澄清一下:问题是在一段时间内完全停止脚本执行,而不是延迟执行某些代码,这对于setTimeout或setInterval来说都是一个任务。

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

setTimout和setInterval不要停止脚本执行,就像这里的一些人看起来顶级思考。刚刚注册了一个推迟运行的函数。当超时/间隔等待时,脚本的其余部分将继续运行。

由于JavaScript的异步性质,“阻止”任何代码执行的唯一方法是非常难看且绝对不推荐的while循环运行一段时间。 因为JavaScript本身在一个单独的线程中运行(我们这里不讨论WebWorkers API ......)。这将阻止任何JS代码运行,直到该循环结束。但那真的很糟糕......

如果您的程序无法在没有睡眠()的情况下工作,也许您应该重新考虑您的方法。

答案 3 :(得分:3)

这个答案可能有点烦人,但是没有它:-)。

由于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,有两件事需要记住。它不是一种过程语言,NOR是一种面向对象的语言。 Javascript是一种具有复杂事件管理模型的函数式语言。所以你必须用这些术语思考。

这也是有道理的,因为典型的javascript机器是一个gui(网络浏览器),它在设计时不想在尝试处理某些东西时完全阻止。想象一下,当一个页面正在做某事时,你的浏览器会完全锁定,你想要扼杀那些为你做这件事的程序员。

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

虽然当你想要做一些微不足道的事情时这是一个不方便的编程,你可能会使用暂停等待可能会遇到竞争条件的方式,并且有一种更合适的方式可以解决这个问题。效果“你试图实现。

如果您发布特殊情况,可能会有更多关于如何处理此类情况的信息。

干杯,

答案 4 :(得分:3)

  

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

这是创造性的,但它只允许用户与模态对话框中的任何内容进行交互,持续时间长短。浏览器的其余部分仍然保持挂起状态,就像您刚刚调用残酷的while (new Date().getTime()<t1);循环一样。

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

  

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

你实际上想睡觉的是什么?如果不返回事件循环或触发模式对话框,您将无法获得任何屏幕更新或用户交互,因此我看不到内联睡眠将为您做什么。你肯定不能这样做动画。

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

ETA:

  

我想用sync api编写ORM,以便开发人员可以更轻松地使用它。要将此异步桥接到同步api,我需要像睡眠这样的东西。

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

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

理论上,您可以打开一个modalDialog,在<{1}}的窗口中执行异步Web SQL数据库调用,并让modalDialog将结果返回给调用者中的同步代码窗口的脚本。但是,目前没有支持modalDialog openDatabase的浏览器!

答案 5 :(得分:1)

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

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