【问题标题】:What is the JavaScript version of sleep()?sleep() 的 JavaScript 版本是什么?
【发布时间】:2009-06-04 14:41:10
【问题描述】:

有没有比下面的pausecomp 函数 (taken from here) 在 JavaScript 中设计 sleep 更好的方法?

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

这不是Sleep in JavaScript - delay between actions的重复;我希望在函数中间有一个真正的睡眠,而不是在一段代码执行之前的延迟。

【问题讨论】:

  • 这是在中间设置,如果我使用 setTimeout,while 将继续处理和排队更多的 setTimeouts,最终将同时运行并在它们之间产生一些并发
  • 这是一个可怕的解决方案 - 你将在什么都不做的情况下消耗处理周期。
  • 睡眠的唯一目的是轮询或等待回调 - setInterval 和 setTimeout 都比这更好。
  • 看到人们在不了解 OP 想要什么的情况下拒绝,真是令人惊讶。在某些情况下,您想要真正的睡眠。我现在需要一个 真正的睡眠 来测试浏览器在顶部窗口和 iframe 之间发布和接收消息的行为。让它忙于一段时间似乎是唯一的方法。
  • @DevsloveZenUML 和浏览器环境的设计者和开发者为了用户的利益,决定你不应该有你的愿望,因为在异步应用程序中给某人明确阻止整个页面的能力是疯狂的。

标签: javascript sleep


【解决方案1】:

2017 年 — 2021 年更新

自从 2009 年提出这个问题以来,JavaScript 已经有了显着的发展。所有其他答案现在都已过时或过于复杂。以下是当前的最佳做法:

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

或者作为单行:

await new Promise(r => setTimeout(r, 2000));

或者

const sleep = ms => new Promise(r => setTimeout(r, ms));

将其用作:

await sleep(<duration>);

演示:

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

async function demo() {
    for (let i = 0; i < 5; i++) {
        console.log(`Waiting ${i} seconds...`);
        await sleep(i * 1000);
    }
    console.log('Done');
}

demo();

请注意,

  1. await 只能在以 async 关键字为前缀的函数中执行,或者在 an increasing number of environments 脚本的顶层执行。
  2. await 只暂停当前的async 函数。这意味着它不会阻止脚本其余部分的执行,这在绝大多数情况下都是您想要的。如果您确实需要阻塞构造,请参阅 this answer 使用 Atomics.wait,但请注意大多数浏览器不允许在浏览器的主线程上使用它。

两个新的 JavaScript 特性(截至 2017 年)帮助编写了这个“睡眠”函数:

兼容性

如果由于某种原因您使用的 Node 早于 7(达到了 end of life in 2017),或者针对的是旧浏览器,async/await 仍然可以通过 Babel 使用(一个工具可以@ 987654334@ JavaScript + 将新功能转换为普通的旧 JavaScript),带有transform-async-to-generator 插件。

【讨论】:

  • 这里有很棒的东西。我想知道,在 JS 调用“睡眠”模式后,这如何影响或与现代浏览器的“活动”/“非活动”状态相关?浏览器是否可以像一般 JS 预期的那样阻止睡眠,以便稍后在变为“活动”时调用,或者它是否具有不同的行为?
  • 目前浏览器对此的支持是什么?在绝大多数浏览器或至少所有常见浏览器都支持此解决方案之前,我不会认为以前的解决方案是“过时的”。相反,在得到广泛支持之前,我会认为这个解决方案很有趣,但无法使用/不切实际。
  • @AlvinThompson:大多数现代 Web 开发都使用转译器,因此本机浏览器支持比更简洁、更面向未来的代码更重要。无论如何,请参阅caniuse
  • @jacroe - 转译器处理箭头函数以及异步/等待(无论如何都会导致 IE 吐血)
  • oneliner await new Promise(r =&gt; setTimeout(() =&gt; r(), 2000));
【解决方案2】:

(见updated answer for 2016

我认为想要执行一个动作,等待,然后执行另一个动作是完全合理的。如果您习惯于使用多线程语言进行编写,您可能会想到让执行一段时间,直到您的线程唤醒。

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

因此,您几乎无法接受其他人的建议——您需要将代码分解为多个函数。

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

【讨论】:

  • 这根本不是一个正确的答案。如果 Javascript 没有睡眠功能,那只是因为 ECMAScript 不需要它。它是负责 Javascript 设计的机构的设计选择。可以使 Javascript 运行时在运行下一行代码之前等待给定的时间,但它被选择不这样做。
  • 睡眠可以在 JavaScript 中完美实现,尽管不是实时精度。毕竟它是一个基于事件的系统。如果异步调用完成,则触发事件。我看不出为什么在发出 sleep() 之后,控制权返回给浏览器直到睡眠结束,将控制权返回给调用函数时,同样不可能。是的,我也同意有时睡觉很方便,尤其是当开发人员在你把设计搞砸之前,除了完全重构而你没有时间之外别无他法
  • 试试 Hypnotic,它遵循这个想法:coolwanglu.github.io/hypnotic/web/demo.html
  • 有一种情况,无论你进行多少重构,超时都无法解决问题:如果你在服务器端运行,客户端正在等待数据,而你没有t 可以直接访问连接以将其传递给超时回调。例如,在流星中,您可以在一个方法中运行。在这种情况下,您应该考虑使用未来,如下所述:stackoverflow.com/questions/12569712/…
  • 我同意为什么 sleep() 在 JS 中是不可能的,并且大多数时候有更好的方法来做事。但我仍然认为引擎将所有事物联系起来的方式是一个设计缺陷。没有理由该语言不能将 sleep() 函数限制为特定的脚本、页面或函数,而引擎不会像疯子一样破坏 CPU 并冻结应用程序。现在是 2015 年,您不应该使用 while(1) 使整个 Web 浏览器崩溃。我们有 Flash 来处理类似的事情。
【解决方案3】:

在 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!
});

【讨论】:

  • 通过关闭方式。 function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
  • 好的,如果代码不打算在网页中使用怎么办?
  • @EugenioMiró 如果代码不打算在网页中使用,请让主机的对象模型实现睡眠方法。 -- 我认为这个问题是针对暴露在网页上运行的 javascript 的 DOM 的。
  • @Nosredna 是的,我们了解如何进行异步调用,这对我们 sleep() 没有帮助。我希望我的呼叫按特定顺序进行,并以特定顺序返回数据。我在 for 循环中有 5 个级别。我想阻止执行。真正的睡眠方法不会“减慢浏览器速度”,睡眠将控制权交还给浏览器和任何其他需要 CPU 时间的线程,而它仍然处于阻塞状态。
  • @Tim 循环安全版本:for(i=0; i&lt;5; i++) { (function(i) { setTimeout(function() { console.log(i); }, 1000*i); })(i); }
【解决方案4】:

Firebug(可能还有其他 JavaScript 控制台)中,点击回车后什么也没有发生,只有在指定的睡眠持续时间之后(...)

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

使用示例:

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

function sleepThenAct(){
    sleepFor(2000);
    console.log("Hello, JavaScript sleep!");
}

sleepThenAct()

注意:仅用于调试和开发

【讨论】:

  • 这不是答案。它与问题中的代码完全相同,只是稍微短一些。
  • 忙着等待,真的吗?在 JS 中?几秒钟?如果我发现一个网站这样做,它将被阻止。
  • @mafu 这就是为什么它说only for debug/dev... rolleyes
  • 永远不要这样做。这将使 CPU 在其执行的核心上达到 100% 并阻止它。
  • 这是有用的,也许是在命令行 javascript 应用程序中睡眠的唯一方法,因为 async/await 没有帮助。
【解决方案5】:

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

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

做到这一点的方法是将你的功能分解成前后部分。

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

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

确保您的函数名称仍能准确描述每个部分的功能(即 GatherInputThenWait 和 CheckInput,而不是 funcPart1 和 funcPart2)

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

正如 cmets 中所指出的,这在循环中绝对不起作用。你可以做一些花哨的(丑陋的)hacking 让它在循环中工作,但总的来说,这只会导致灾难性的意大利面条代码。

【讨论】:

  • 是的。当你有一个循环,甚至是一个嵌套循环时,这就变得棘手了。你必须放弃你的 for 循环,取而代之的是计数器。
  • 触摸。我的意思是,它仍然是可能的,但在这种情况下是丑陋和骇人听闻的。你也可以使用一些静态布尔状态变量,但这也很老套。
  • -1 为此。同样,这并不能回答问题。这更像是“如何异步执行函数”之类的问题的答案,这与“如何阻止代码执行”有很大不同。
  • @Nosredna 不,你会使用闭包。例如:function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }for(var X = 0; X &lt; 3;X++) { foo(X); } - X 的 被传递到 foo,然后在最终调用 foo_continue 时以名称 index 重用。
  • @Alexander 当然可以,因为 setTimeout() 的目的是通过异步运行代码来防止浏览器锁定。在 setTimeout 版本中将console.log() 放入foo_continue() 中,您会得到相同的结果。
【解决方案6】:

为了 $DEITY 的爱,请不要做忙等待睡眠功能。 setTimeoutsetInterval 做你需要的一切。

var showHide = document.getElementById('showHide');
setInterval(() => {
    showHide.style.visibility = "initial";
    setTimeout(() => {
        showHide.style.visibility = "hidden"
    }, 1000);
    ;
}, 2000);   
&lt;div id="showHide"&gt;Hello! Goodbye!&lt;/div&gt;

每两秒间隔隐藏文本一秒。这显示了如何使用 setInterval 和 setTimeout 每秒显示和隐藏文本。

【讨论】:

  • 不是所有的东西:setInterval 对轮询的印象要好得多。
  • 除非您需要同步睡眠,在这种情况下这是一个完全有效的问题。
  • 我想我们中的许多人可能忘记了 JavaScript 不是一种仅限浏览器的语言。这个家伙可能正在创建一个需要短暂暂停的 Node 命令行实用程序,而无需处理 setTimeout 带来的所有变量范围问题。
  • @PhilLaNasa:如果句法闭合仍然让一个人感到害怕,那么一个人真的需要安全并通过节点 101 工作。
  • @PhilLaNasa:闭包不是 JS 101 的任何上下文都需要重新设计完整的课程,统计。
【解决方案7】:

如果(像我一样)您使用带有 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.
   */
}

【讨论】:

  • @RousseauAlexandre 不正确。它是使用 Rhino 的 JavaScript(当时,现在它可能同样是 Nashorn)
【解决方案8】:

如果您使用 jQuery,实际上有人创建了一个“延迟”插件,它只不过是 setTimeout 的包装器:

// Delay Plugin for jQuery
// - http://www.evanbot.com
// - © 2008 Evan Byrne

jQuery.fn.delay = function(time,func){
    this.each(function(){
        setTimeout(func,time);
    });

    return this;
};

然后您可以按预期在一行函数调用中使用它:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');

【讨论】:

  • 这不是一个糟糕的解决方案。保持上下文和可链接性。
  • 从 jQuery 1.4 开始,.delay() 是 jQuery 的一部分(尽管语义与上述实现不同)。 api.jquery.com/delay
  • 这个问题绝对缺少的是jQuery answer。很高兴我们得到了它!
  • 如果您需要两个独立呼叫之间的延迟,可以。如果您需要延迟来减慢循环,则不需要。
【解决方案9】:

用途:

  await new Promise(resolve =&gt; setTimeout(resolve, 2000));

确保您的调用函数是异步的。这已经过验证并且工作正常。

【讨论】:

  • 最后。唯一的答案。
【解决方案10】:

我也搜索过睡眠解决方案(不适用于生产代码,仅用于开发和测试)并找到了这篇文章:

JavaScript sleep() or wait()

...还有一篇关于客户端解决方案的文章:JavaScript sleep

另外,当您调用alert() 时,您的代码也会暂停,同时显示警报——您需要找到一种不显示警报但获得相同效果的方法。 :)

【讨论】:

  • 我同意,很多人都在说,“不,不要在生产代码中这样做!”是的,嗯,我不想。我想在一次性测试代码中完成它,因此我不想花很多时间制作一个优雅的解决方案。
【解决方案11】:

给你。正如代码所说,不要成为一个糟糕的开发人员并在网站上使用它。这是一个开发实用功能。

// Basic sleep function based on ms.
// DO NOT USE ON PUBLIC FACING WEBSITES.
function sleep(ms) {
    var unixtime_ms = new Date().getTime();
    while(new Date().getTime() < unixtime_ms + ms) {}
}

【讨论】:

  • 这与OP的基本相同。
  • 更准确地说,这是 OP 要求的替代方案。
【解决方案12】:

这是一个使用同步 XMLHttpRequest 的简单解决方案:

function sleep(n){
  var request = new XMLHttpRequest();
  request.open('GET', '/sleep.php?n=' + n, false);  // `false` makes the request synchronous
  request.send(null);
}

文件sleep.php的内容:

<?php sleep($_GET['n']);

现在调用它:

sleep(5);

【讨论】:

  • @lukad,如果可行,请使用setTimeout(),但如果这样做意味着要解开 1000 行回调,这可能看起来不像是在开玩笑。
  • 独特的方法,但不幸的是,非异步 XMLHttpRequests 已被弃用,并将在未来被删除。这很有趣,因为这个事实是我首先提出这个问题的原因。
  • 这实际上是 IMO 的一个好主意。虽然我认为 sleep API(请求 URL)不应该公开,因为它可能会被滥用。
  • 很好,但您知道是否有时互联网速度很慢或网站 ping 时间长于它会使脚本休眠超过参数时间。就像如果您使用sleep(300) 并且网站需要 150 毫秒的响应时间,那么 javascript 代码将休眠 450 毫秒。如果浏览器失去互联网连接,它将仅工作 0ms。所以这不是更好的解决方案
【解决方案13】:

自 2021 年 4 月 (Node.js 16+) 起,setTimeout() 的新承诺版本可用:

import { setTimeout } from 'timers/promises'

const res = await setTimeout(2000, 'result')

console.log(res);  // Prints 'result'

感谢@kigiri。见官方文档: https://nodejs.org/api/timers.html#timerspromisessettimeoutdelay-value-options

【讨论】:

【解决方案14】:

第一:

定义一个你想像这样执行的函数:

function alertWorld(){
  alert("Hello, World!");
}

然后使用 setTimeout 方法安排其执行:

setTimeout(alertWorld, 1000)

注意两点

  • 第二个参数是以毫秒为单位的时间
  • 作为第一个参数,您只需传递函数的名称(引用),不带括号

【讨论】:

  • 问题是问一种在阻塞的 wy 中睡觉的方法。 setTimeout 不这样做。它在宏任务队列中排队。
【解决方案15】:

内联:

(async () => await new Promise(resolve => setTimeout(resolve, 500)))();

这里的 500 是虚拟机在移动到下一行代码之前等待的时间(以毫秒为单位)。

一点tldr;

基本上,当您创建一个 Promise 时,它​​会在创建时返回一个 observable,在回调中提供一个 resolve 的引用,用于在数据/响应可用时移交数据/响应。在这里,在 500 毫秒后通过setTimeOut 调用解析,直到解析未执行,外部作用域正在等待进一步进行,因此创建了一个假阻塞。它与非阻塞(或调用其他语言中可用的非线程保留睡眠)完全不同,因为线程和很可能 UI 以及网页/节点应用程序的任何其他正在进行的任务将被阻塞,主线程将专门用于等待承诺解决。

【讨论】:

  • 我无法理解函数解析被定义为调用自身的部分。这有什么意义?
  • @sureshvv 检查更新。
  • 如果想放在异步函数的中间,只需使用await new Promise(resolve =&gt; setTimeout(resolve, sleepMiliseconds))
【解决方案16】:

我个人喜欢简单的:

function sleep(seconds){
    var waitUntil = new Date().getTime() + seconds*1000;
    while(new Date().getTime() < waitUntil) 
        true;
}

然后:

sleep(2); // Sleeps for 2 seconds

p5.js 中创建脚本时,我一直在使用它来创建虚假加载时间。

【讨论】:

  • 我认为这是主要问题的最优化版本:它在循环内不做任何数学运算,只是一个简单的比较。读起来有点难。
  • 永远不要那样做。您是否在此功能工作时检查了 CPU 使用率?如果你给它足够的时间,它应该接近 100%。
  • @hegez:鉴于循环无论如何都会运行固定的挂钟时间,看来优化循环有点离题了。
  • @noego 怎么样?我刚刚在 Node 10 中测试过,CPU 使用率没有任何变化
  • @melMass 这个函数只是通过保持 CPU 100% 繁忙来阻塞节点线程 n 秒。由于这两个原因(阻塞+ CPU杀手),这个“解决方案”是一个非常糟糕的主意。等待必须是非阻塞的,因此是异步的。
【解决方案17】:

让事情看起来像大多数人想要的更好的解决方案是使用匿名函数:

alert('start');
var a = 'foo';
// Lots of code
setTimeout(function(){  // Beginning of code that should run AFTER the timeout
    alert(a);
    // Lots more code
}, 5000);  // Put the timeout here

这可能是最接近你想要的东西的东西。

请注意,如果您需要多次睡眠,这可能会很快变得难看,您实际上可能需要重新考虑您的设计。

【讨论】:

  • 这是在桌面浏览器和旧手机上为我工作的那个。我试过的其他方法都没有。
【解决方案18】:

2019 年更新使用Atomics.wait

它应该在Node.js 9.3 或更高版本中工作。

我需要一个非常准确的 Node.js 计时器,它非常适合。

但是,浏览器的支持似乎非常有限。

let ms = 10000;
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);

运行了几个 10 秒计时器基准测试。

使用 setTimeout,我会收到长达 7000 微秒(7 毫秒)的错误。

使用 Atomics,我的错误似乎保持在 600 微秒(0.6 毫秒)以下

2020 年更新:总结

function sleep(millis){ // Need help of a server-side page
  let netMillis = Math.max(millis-5, 0); // Assuming 5 ms overhead
  let xhr = new XMLHttpRequest();
  xhr.open('GET', '/sleep.jsp?millis=' + netMillis + '&rand=' + Math.random(), false);
  try{
    xhr.send();
  }catch(e){
  }
}

function sleepAsync(millis){ // Use only in async function
  let netMillis = Math.max(millis-1, 0); // Assuming 1 ms overhead
  return new Promise((resolve) => {
    setTimeout(resolve, netMillis);
  });
}
function sleepSync(millis){ // Use only in worker thread, currently Chrome-only
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, millis);
}

function sleepTest(){
  console.time('sleep');
  sleep(1000);
  console.timeEnd('sleep');
}

async function sleepAsyncTest(){
  console.time('sleepAsync');
  await sleepAsync(1000);
  console.timeEnd('sleepAsync');
}

function sleepSyncTest(){
  let source = `${sleepSync.toString()}
    console.time('sleepSync');
    sleepSync(1000);
    console.timeEnd('sleepSync');`;
  let src = 'data:text/javascript,' + encodeURIComponent(source);
  console.log(src);
  var worker = new Worker(src);
}

其中的服务器端页面,例如sleep.jsp,看起来像:

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>

【讨论】:

  • 在我看来比公认的解决方案要好,因为在调用者中没有 async/await 就无法将其实现为简单的函数。
  • 是的,只要你知道这是阻塞的,这通常不是一件好事
  • 非常酷,但事实上只有Chrome and Firefox 才真正支持这一点,这并不能使它非常适合在网络上使用。 (2019 年 11 月)
  • 这就是我要找的答案!我无法访问异步函数:D
  • 在极少数需要阻塞的情况下,这是正确的解决方案。我希望在写博客之前看到你的答案,我认为我找到了一个新颖的解决方案!无论如何,有关使用 Service Worker 的 XHR 解决方案的详细解释、演示和附加变体:jasonformat.com/javascript-sleep
【解决方案19】:

单线使用Promises

const sleep = t => new Promise(s => setTimeout(s, t));

演示

const sleep = t => new Promise(s => setTimeout(s, t));
// Usage
async function demo() {
    // Count down
    let i = 6;
    while (i--) {
        await sleep(1000);
        console.log(i);
    }
    // Sum of numbers 0 to 5 using by delay of 1 second
    const sum = await [...Array(6).keys()].reduce(async (a, b) => {
        a = await a;
        await sleep(1000);
        const result = a + b;
        console.log(`${a} + ${b} = ${result}`);
        return result;
    }, Promise.resolve(0));
    console.log("sum", sum);
}
demo();

【讨论】:

  • 复制/意大利面是真实的
【解决方案20】:

没有任何依赖的最短解决方案:

await new Promise(resolve => setTimeout(resolve, 5000));

【讨论】:

  • 它在 IE11 中不起作用。我们得到箭头函数的语法错误。
  • @Java-DK 使用await new Promise(function(resolve) { setTimeout(resolve, 5000); });
  • 这与Ahmed Mohammedali's answer 相同(首先发布)。
  • @PeterMortensen,它是从我在 2018 年 3 月给出的不同答案中复制而来的:stackoverflow.com/a/49139664/440168
【解决方案21】:

对于浏览器,我同意 setTimeout 和 setInterval 是可行的方法。

但对于服务器端代码,它可能需要一个阻塞函数(例如,这样可以有效地进行线程同步)。

如果您使用Node.jsMeteor,您可能会遇到在光纤中使用 setTimeout 的限制。这是服务器端睡眠的代码。

var Fiber = require('fibers');

function sleep(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

见:Node.js Fibers, Sleep

【讨论】:

  • Server may require a blocking function... 我不明白如何强行阻塞 Node 的唯一线程并让您的整个服务器在几秒钟内无响应是个好主意,但无论如何
【解决方案22】:

这里的大多数答案都是错误的,或者至少已经过时了。 JavaScript 没有理由必须是单线程的,事实上也不是。今天所有的主流浏览器都支持工人。在此之前,Rhino 和 Node.js 等其他 JavaScript 运行时支持多线程。

“JavaScript 是单线程的”不是一个有效的答案。例如,在 worker 中运行 sleep 函数不会阻塞 UI 线程中运行的任何代码。

在支持生成器和 yield 的较新运行时中,可以在单线程环境中为 sleep 函数带来类似的功能:

// This is based on the latest ES6 drafts.
// JavaScript 1.7+ (SpiderMonkey/Firefox 2+) syntax is slightly different

// Run code you want to sleep here (omit star if using JavaScript 1.7)
function* main(){
    for (var i = 0; i < 10; i++) {
        // To sleep for 10 milliseconds 10 times in a row
        yield 10;
    }

    yield 5;
    console.log('I just slept 5 milliseconds!');
}

// Resume the given generator after ms milliseconds
function resume(ms, generator){
    setTimeout(function(){
        // Omit .value if using JavaScript 1.7
        var nextSleep = generator.next().value;
        resume(nextSleep, generator);
    }, ms);
}

// Initialize a generator and get first sleep for the recursive function
var
    generator = main(),
    firstSleep = generator.next().value;

// Initialize recursive resume function
resume(firstSleep, generator);

这种对睡眠的模仿不同于真正的睡眠功能,因为它不会阻塞线程。它只是 JavaScript 当前 setTimeout 函数之上的糖。此功能类型已在 Task.js 中实现,现在应该可以在 Firefox 中使用。

【讨论】:

  • Workers 没有在 IE 中实现,至少到 10 版为止。目前代表大量用户。
  • 是的,即便如此,使用多个 worker 实现 sleep 也是不切实际的。如果使用 Node.js 生成器功能已经实现并且可以按照描述使用。到目前为止,主流浏览器还没有全部实现生成器。
【解决方案23】:

我会将 setTimeOut 封装在 Promise 中,以便与其他异步任务的代码保持一致:Fiddle 中的演示

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

它是这样使用的:

sleep(2000).then(function() {
   // Do something
});

如果你习惯使用 Promises,语法很容易记住。

【讨论】:

  • 为什么这比只使用 setTimeout(function(){/*do something*/}, 2000); 更好?
【解决方案24】:

我已经搜索/谷歌了很多关于 JavaScript 睡眠/等待的网页...如果您希望 JavaScript “运行、延迟、运行”,则没有答案...大多数人得到的是“RUN,RUN(无用的东西),RUN”或“RUN,RUN +延迟运行”......

我想: 这是一个可行的解决方案......但你必须砍掉你的运行代码......: 是的,我知道,这只是一个更易于阅读的重构......仍然......

示例 1:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setInterval
var i = 0;

function run() {
    // Pieces of codes to run
    if (i == 0){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i == 1){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i == 2){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i >2){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i == 5){document.getElementById("id1").innerHTML= "<p>all code segment finished running</p>"; clearInterval(t); } // End interval, stops run
    i++; // Segment of code finished running, next...
}

run();
t = setInterval("run()", 1000);

</script>
</body>
</html>

示例 2:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setTimeout
var i = 0;

function run() {
    // Pieces of codes to run, can use switch statement
    if (i == 0){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>"; sleep(1000);}
    if (i == 1){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>"; sleep(2000);}
    if (i == 2){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>"; sleep(3000);}
    if (i == 3){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>";} //stops automatically
    i++;
}

function sleep(dur) {t=setTimeout("run()", dur);} // Starts flow control again after 'dur'

run(); // Starts
</script>
</body>
</html>

示例 3:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setTimeout
var i = 0;

function flow() {
    run(i);
    i++; // Code segment finished running, increment i; can put elsewhere
    sleep(1000);
    if (i == 5) {clearTimeout(t);} // Stops flow, must be after sleep()
}

function run(segment) {
    // Pieces of codes to run, can use switch statement
    if (segment == 0){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 1){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 2){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
}

function sleep(dur) {t=setTimeout("flow()", dur);} // Starts flow control again after 'dur'

flow(); // Starts flow
</script>
</body>
</html>

示例 4:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setTimeout, switch
var i = 0;

function flow() {
    switch(i)
    {
        case 0:
            run(i);
            sleep(1000);
            break;
        case 1:
            run(i);
            sleep(2000);
            break;
        case 5:
            run(i);
            clearTimeout(t); // Stops flow
            break;
        default:
            run(i);
            sleep(3000);
            break;
    }
}

function run(segment) {
    // Pieces of codes to run, can use switch statement
    if (segment == 0){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 1){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 2){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    i++; // Current segment of code finished running, next...
}

function sleep(dur) {t=setTimeout("flow()", dur);} // Starts flow control again after 'dur'

flow(); // Starts flow control for first time...
</script>
</body>
</html>

【讨论】:

  • 好的,这适用于 setTimeput,但很难看出发生了什么。使用 setTimeout 本身比这更容易。
【解决方案25】:

由于Node.js 7.6,您可以将utils 模块中的promisify 函数与setTimeout 结合使用。

const sleep = require('util').promisify(setTimeout)

一般用法

async function main() {
    console.time("Slept for")
    await sleep(3000)
    console.timeEnd("Slept for")
}

main()

问题用法

async function asyncGenerator() {
    while (goOn) {
      var fileList = await listFiles(nextPageToken);
      await sleep(3000)
      var parents = await requestParents(fileList);
    }
  }

【讨论】:

    【解决方案26】:

    如果您必须处理同步执行,我可以理解睡眠功能的目的。 setInterval 和 setTimeout 函数创建一个并行执行线程,将执行序列返回给主程序,如果您必须等待给定的结果,这是无效的。当然,可以使用事件和处理程序,但在某些情况下不是预期的。

    【讨论】:

      【解决方案27】:
      function sleep(milliseconds) {
        var start = new Date().getTime();
        for (var i = 0; i < 1e7; i++) {
          if ((new Date().getTime() - start) > milliseconds){
            break;
          }
        }
      }
      

      【讨论】:

      • 和真题一样。让它成为真正的答案没什么意义。
      • 不是一个好的解决方案 - 在 Selenium 的 JavaScriptExecutor 中使用它会使我的 Chrome 浏览器在 2104 MacBook Pro 上挂起大约 50% 的时间。
      • 解释一下。想法/要点是什么?它与以前的答案有什么不同?
      【解决方案28】:

      如果您想要比setTimeoutsetInterval 更少笨重的函数,您可以将它们包装在只颠倒参数顺序并给它们起好名字的函数中:

      function after(ms, fn){ setTimeout(fn, ms); }
      function every(ms, fn){ setInterval(fn, ms); }
      

      CoffeeScript 版本:

      after = (ms, fn)-> setTimeout fn, ms
      every = (ms, fn)-> setInterval fn, ms
      

      然后您可以将它们与匿名函数很好地结合使用:

      after(1000, function(){
          console.log("it's been a second");
          after(1000, function(){
              console.log("it's been another second");
          });
      });
      

      现在它很容易读为“N 毫秒后,...”(或“每 N 毫秒,...”)

      【讨论】:

        【解决方案29】:

        你不能在 JavaScript 中做这样的睡眠,或者更确切地说,你不应该这样做。运行 sleep 或 while 循环将导致用户的浏览器挂起,直到循环完成。

        使用您引用的链接中指定的计时器。

        【讨论】:

          【解决方案30】:

          可以使用 Java 的 sleep 方法来完成。我在 Firefox 和 Internet Explorer 中对其进行了测试,它不会锁定计算机、占用资源或导致无休止的服务器命中。对我来说,这似乎是一个干净的解决方案。

          首先,您必须在页面上加载 Java 并使其方法可用。为此,我这样做了:

          <html>
          <head>
          
          <script type="text/javascript">
          
            function load() {
              var appletRef = document.getElementById("app");
              window.java = appletRef.Packages.java;
            } // endfunction
          
          </script>
          
          <body onLoad="load()">
          
          <embed id="app" code="java.applet.Applet" type="application/x-java-applet" MAYSCRIPT="true" width="0" height="0" />
          

          然后,当您想要在 JavaScript 代码中轻松暂停时,您所要做的就是:

          java.lang.Thread.sleep(xxx)
          

          其中 xxx 是以毫秒为单位的时间。在我的情况下(作为证明),这是一家非常小的公司后端订单履行的一部分,我需要打印一张必须从服务器加载的发票。我通过将发票(作为网页)加载到 iFrame 中然后打印 iFrame 来做到这一点。

          当然,我必须等到页面完全加载后才能打印,所以 JavaScript 代码不得不暂停。我通过让发票页面(在 iFrame 中)使用 onLoad 事件更改父页面上的隐藏表单字段来完成此操作。父页面上打印发票的代码如下所示(为了清楚起见,剪掉了无关部分):

          var isReady = eval('document.batchForm.ready');
          isReady.value = 0;
          
          frames['rpc_frame'].location.href = url;
          
          while (isReady.value == 0) {
            java.lang.Thread.sleep(250);
          } // endwhile
          
          window.frames['rpc_frame'].focus();
          window.frames['rpc_frame'].print();
          

          所以用户按下按钮,脚本加载发票页面,等待,每季度检查一次发票页面是否完成加载,然后弹出打印对话框让用户将其发送到打印机。 QED。

          【讨论】:

          • 在考虑作者想要实现的简单事情时,这似乎是相当可怕的解决方案。
          • 这取决于已弃用的 Java Applet。
          猜你喜欢
          • 2010-09-15
          • 1970-01-01
          • 1970-01-01
          • 2013-01-26
          相关资源
          最近更新 更多