假设我想在一段时间内阻止Javascript执行出于某种奇怪的原因,我该怎么做呢。 JS中没有sleep()。请不要说做while()循环,因为那很糟糕。我可以做一个window.showModalDialog并在一个非常小的时间的setTimeout的模态对话框中放置一个window.close,这样用户就不会注意到该对话框。这就像睡眠一段时间,如果需要我可以多次调用。还有其他方法吗?
详细说明,我的用例是HTML5 SQL数据库已经给出了异步api,但我想将它用于一个小商店永远不会大的小型webapp。因此不需要异步api,因为小商店上的查询将在客户端运行。所以我想编写一个带有sync api的ORM,以便开发人员可以更轻松地使用它。要将此异步桥接到同步api,我需要像睡眠这样的东西。
答案 0 :(得分:14)
window.setTimeout
或window.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.setTimeout
和window.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");
}
运行此功能时,您将看到三条警报消息,延迟介于第二和第三之间:
答案 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添加脚本标记以指向此。
当然,它需要服务器端实现,但是,它允许您在任何特定点停止页面。正如其他人之前所说,这将阻止整个浏览器,而不仅仅是你的脚本。