题 什么是sleep()的JavaScript版本?


有没有更好的方法来设计一个 sleep 在JavaScript中比以下 pausecomp 功能(取自这里)?

function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

这不是重复的 在JavaScript中睡眠 - 在动作之间延迟;我想要一个 真正的睡眠 在函数的中间,而不是在一段代码执行之前的延迟。


1527
2017-10-07 09:44


起源


它是设置在一段时间,如果我使用setTimeout,while将继续处理并排队更多的setTimeouts,它们最终会同时运行并在它们之间产生一点并发性 - fmsf
这是一个可怕的解决方案 - 你将在什么也不做的时候咀嚼处理周期。 - 17 of 26
睡眠的唯一目的是轮询或等待回调 - setInterval和setTimeout都比这更好。 - annakata
也许你可以用JavaScript继续传递样式做你想做的事。看一眼 本文。 - Ognyan Dimitrov


答案:


2017年更新

自从2009年问到这个问题以来,JavaScript已经发生了很大的变化。所有其他答案现在已经过时或过于复杂。这是目前的最佳做法:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
  console.log('Taking a break...');
  await sleep(2000);
  console.log('Two second later');
}

demo();

就是这个。 await sleep(<duration>)

您可以直接试用此代码 在Runkit上。注意,

  1. await 只能在以前缀为的函数中执行 async 关键词。 Runkit在执行之前将代码包装在异步函数中。
  2. await 只暂停当前 async 功能

两个新的JavaScript功能帮助编写了这个实际的“睡眠”功能:

兼容性

如果由于某种原因您使用的是超过7的节点,或者是针对旧版浏览器, async/await 仍然可以通过 巴别塔 (将成为一种工具 transpile JavaScript +新功能转换为普通的旧JavaScript),用 transform-async-to-generator 插入。跑

npm install babel-cli --save

创建 .babelrc 有:

{
  "plugins": [
    "transform-async-to-generator",
  ]
}

然后运行你的代码

node_modules/babel-cli/bin/babel-node.js sleep.js

但是,如果您使用的是Node 7或更高版本,或者您的目标是现代浏览器,那么您也不需要这样做。


1089



好东西在这里。我想知道,在JS调用“睡眠”模式后,这会如何影响或与现代浏览器“活动”/“非活动”状态相关?浏览器是否可以像普通JS一样阻止睡眠,以后在变为“活动”时调用,或者它具有不同的行为? - Andre Canilho
目前的浏览器支持是什么?在绝大多数浏览器或至少所有常见浏览器都支持此解决方案之前,我不认为以前的解决方案是“过时的”。相反,我会认为这个解决方案很有意思,但在得到广泛支持之前无法使用/不切实际。 - Alvin Thompson
@AlvinThompson:大多数现代Web开发使用转换器,因此本机浏览器支持比清洁和更具前瞻性的代码更重要。无论如何,请看 我可以用吗。 - Dan Dascalescu
这不是“真正的睡眠”,也没有回答这个问题。要求的人明确区分 stackoverflow.com/questions/758688/sleep-in-javascript 和他的问题。在实际睡眠中,不能执行其他代码(除非在其他线程中)。这个答案对另一个问题有好处。 - niry
@jacroe - 转换器处理箭头函数以及async / await(这会导致IE呕吐血液) - Jaromanda X


(见 更新2016年的答案

我认为想要执行某个操作,等待,然后执行其他操作是完全合理的。如果您习惯于使用多线程语言编写,那么在线程唤醒之前,您可能会想要在一段时间内执行执行。

这里的问题是JavaScript是一个基于事件的单线程模型。虽然在特定情况下,让整个引擎等待几秒钟可能会很好,但总的来说这是不好的做法。假设我想在编写自己的函数时使用你的函数?当我打电话给你的方法时,我的方法都会冻结。如果JavaScript可以某种方式保存你的函数的执行上下文,将它存储在某个地方,然后将其恢复并稍后继续,然后就可以发生睡眠,但这基本上就是线程化。

所以你几乎坚持别人的建议 - 你需要将你的代码分解成多个功能。

那么你的问题是一个错误的选择。没有办法以你想要的方式睡觉,你也不应该寻求你建议的解决方案。


830



这根本不是一个正确的答案。如果Javascript没有睡眠功能,那只是因为ECMAScript不需要它。它是负责Javascript设计的机构的设计选择。在运行下一行代码之前,Javascript运行时可能会等待一段给定的时间,但是选择不这样做。 - Didier A.
睡眠可以在JavaScript中完美实现,但不是实时精确。毕竟它是一个基于事件的系统。如果完成异步调用,则会触发事件。我发现当发出sleep()之后无法实现同样的目的,之后控制权返回到浏览器,直到睡眠结束,将控制权返回给调用函数。是的,我也同意有时睡觉很方便,尤其是开发人员在你搞砸了设计之前,除了完全重构之外没有别的办法,你没有时间 - Lawrence
尝试Hypnotic,遵循这个想法: coolwanglu.github.io/hypnotic/web/demo.html - Tezcat
调用javascript单线程只是一个神话。虽然它在技术上可能是正确的,但从功能上来说它就像一个多线程的语言。模拟fork()非常简单,虽然yield()实际上不是可实现的,但是通过使用共享内存来锁定/信号量可以非常接近。对于普通程序员来说,将其视为多线程是有意义的;技术名称仅对该语言的开发人员有用。 - Benubird
我同意为什么 sleep() 在JS中是不可能的,并且大多数时候有更好的方法来做事。但是我仍然会考虑发动机将所有事情联系起来的方式是一个设计缺陷;没有理由语言没有 sleep()功能仅限于特定的脚本,页面或功能,没有引擎破坏CPU并像疯子一样冻结应用程序。这是2015年,你不应该崩溃整个网络浏览器 while(1)。我们有Flash这样的东西。 - Beejor


在JavaScript中,我重写了每个函数,以便它可以尽快结束。您希望浏览器重新进入控制状态,以便进行DOM更改。

每次我想在我的功能中间睡觉时,我都会重构使用 setTimeout()

我要编辑这个答案因为我觉得这很有用:

在任何语言中臭名昭着的睡眠或延迟功能都备受争议。有些人会说应该总是有一个信号或回调来激发给定的功能,其他人会争辩说,有时候任意延迟的时刻都是有用的。我说每个人都有自己和一个规则在这个行业中永远不会有任何规定。

编写一个sleep函数很简单,使用JavaScript Promises更加实用:

// sleep time expects milliseconds
function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});

590



通过关闭的方式。 function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); } - chaos
好的,如果代码不打算在网页中使用怎么办? - Eugenio Miró
@EugenioMiró如果代码不打算在网页中使用,请让主机的对象模型实现sleep方法。 - 我认为问题是针对暴露于网页上运行的javascript的DOM。 - BrainSlugs83
@Nosredna是的,我们了解如何进行异步调用,这对我们没有帮助睡眠()。我希望我的调用按特定顺序进行,并按特定顺序恢复数据。我在for循环中有5级深度。我想BLOCK执行。一个真正的睡眠方法不会“减慢浏览器的速度”,让睡眠控制回到浏览器以及任何其他需要CPU时间但仍在阻塞的线程。 - BrainSlugs83
这不是问题的答案。 - TMS


仅适用于debug / dev 如果它对某人有用,我发布这个

有趣的东西,在Firebug(可能还有其他的js游戏机)中,只有在指定的睡眠持续时间之后才会在进入后发生任何事情(...)

function sleepFor( sleepDuration ){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ /* do nothing */ } 
}

使用示例:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }

269



这不是答案。它与问题中的代码完全相同,只是略短一些。 - jab
忙着等,真的吗?在JS?几秒钟?如果我抓住一个网站这样做,它将被阻止。 - mafu
@mafu这就是它说的原因 only for debug/dev... 翻白眼 - xDaizu
@mafu这是真的,提出一个适当的例子是非常棘手的,它可能值得拥有自己的问题! - xDaizu
永远不要这样做。这将使CPU在其执行的核心上达到100%并将阻止它。 - noego


我同意其他海报,忙碌的睡眠只是一个坏主意。

但是,setTimeout不会阻止执行,它会在超时设置后立即执行函数的下一行,而不会在超时到期后执行,这样就无法完成睡眠完成的相同任务。

这样做的方法是将您的功能分解为部件之前和之后。

function doStuff()
{
  //do some things
  setTimeout(continueExecution, 10000) //wait ten seconds before continuing
}

function continueExecution()
{
   //finish doing things after the pause
}

确保您的函数名称仍然准确地描述每个部分正在做什么(I.E. GatherInputThenWait和CheckInput,而不是funcPart1和funcPart2)

编辑 

这种方法的目的是在超时之后不执行您决定的代码行,同时仍然将控制权返回给客户端PC以执行其排队的任何其他内容。

进一步编辑

正如评论中指出的那样,这绝对不会在循环中起作用。你可以做一些花哨的(丑陋的)黑客攻击让它在一个循环中工作,但总的来说,这只会造成灾难性的意大利面条代码。


164



是啊。当你有一个循环或一个嵌套循环时,这变得棘手。您必须放弃for循环并改为使用计数器。 - Nosredna
德勤。我的意思是,它仍然是可能的,但在这种情况下是丑陋和hackish。你也可以使用一些静态布尔状态变量,但这也是非常hackish。 - DevinB
-1为此。同样,这不回答这个问题。这更像是“如何异步执行函数”这样的问题的答案,这与“如何阻止代码执行”非常不同。 - Deepak G M
@Nosredna不,你会使用一个闭包。例如: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); } 和 for(var X = 0; X < 3;X++) { foo(X); }  - 值 X被传入 foo,然后在名称下重用 index 什么时候 foo_continue 最终被召唤。 - Izkata
@Alexander当然可以,因为setTimeout()的目的是通过异步运行代码来阻止浏览器锁定。放在 console.log() 内 foo_continue() 在setTimeout版本中,您得到相同的结果。 - Izkata


为了爱$ DEITY,请不要做一个忙碌的等待睡眠功能。 setTimeout 和 setInterval 做你需要的一切。


113



我同意。真的“睡眠”不会冻结整个javascript引擎...... - Skurmedel
不完全是这一切:setInterval对轮询的印象要好得多。 - annakata
这段代码会是什么? 不 阻止JavaScript引擎? - Deniz Dogan
除非你需要睡眠是同步的,否则这是一个完全有效的问题。 - Aaron Dufour
我想很多人可能会忘记JavaScript不是仅限浏览器的语言。这个家伙可能正在创建一个Node命令行实用程序,需要短暂暂停,而不需要处理setTimeout带来的所有变量范围问题。 - Phil LaNasa


我知道这是一个古老的问题,但如果(像我一样)你使用的是与Rhino的Javascript,你可以使用......

try
{
  java.lang.Thread.sleep(timeInMilliseconds);
}
catch (e)
{
  /*
   * This will happen if the sleep is woken up - you might want to check
   * if enough time has passed and sleep again if not - depending on how
   * important the sleep time is to you.
   */
}

109



这是对Java的调用吗? - Ken Sharp
是的,调用Java的线程睡眠。 - mjaggard
这是 Java的 不 使用Javascript - RousseauAlexandre
@RousseauAlexandre不正确。它是 JavaScript的 使用Rhino(当时,它们现在也可能是Nashorn) - mjaggard