3106

有没有sleep比以下pausecomp函数(取自此处)更好的方法来设计 JavaScript 中的 a?

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

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

4

88 回答 88

4089

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中在脚本的顶层执行。
  2. await仅暂停当前async功能。这意味着它不会阻止脚本其余部分的执行,这在绝大多数情况下都是您想要的。如果您确实需要阻塞构造,请使用 来查看此答案,但请注意,大多数浏览器不允许在浏览器的主线程上使用它。Atomics.wait

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

  • Promises,ES2015(又名 ES6)的原生特性。我们还在 sleep 函数的定义中使用了箭头函数。
  • async/await功能允许代码显式等待承诺解决(解决或拒绝)。

兼容性

如果由于某种原因您使用的 Node 早于 7 版(2017 年已停产),或者针对的是旧版浏览器,async/await仍然可以通过Babel使用(一种将JavaScript + 新功能转换为普通旧 JavaScript 的工具) , 用插件。transform-async-to-generator

于 2016-10-07T09:44:56.400 回答
860

(请参阅2016 年的更新答案

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

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

所以你几乎被其他人的建议所困扰——你需要将你的代码分解成多个函数。

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

于 2011-05-13T13:21:37.483 回答
735

在 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!
});
于 2009-06-04T14:46:54.350 回答
337

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

注意:仅用于调试和开发

于 2013-07-30T00:31:49.537 回答
197

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

但是, 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 以执行它已排队的任何其他内容。

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

于 2009-06-04T14:55:29.917 回答
150

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

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

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

于 2009-06-04T14:44:03.713 回答
113

如果(像我一样)你在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.
   */
}
于 2011-11-04T14:16:06.403 回答
73

如果您使用的是 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');
于 2009-06-10T18:50:32.927 回答
59

采用:

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

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

于 2019-06-26T11:27:12.747 回答
52

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

JavaScript sleep() 或 wait()

...这是另一篇有关客户端解决方案的文章:JavaScript sleep

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

于 2011-06-14T20:50:28.753 回答
34

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

// 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) {}
}
于 2012-11-03T02:02:47.950 回答
32

这是一个使用同步 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);
于 2014-11-03T23:22:20.300 回答
29

自 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

于 2021-04-21T02:05:54.480 回答
26

第一的:

定义一个要执行的函数,如下所示:

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

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

setTimeout(alertWorld, 1000)

注意两点

  • 第二个参数是以毫秒为单位的时间
  • 作为第一个参数,您必须只传递函数的名称(引用),不带括号
于 2009-06-04T14:47:52.723 回答
26

我个人喜欢简单的:

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

然后:

sleep(2); // Sleeps for 2 seconds

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

于 2016-11-12T19:56:33.300 回答
23

内联:

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

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

一点tldr;

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

于 2021-05-29T18:06:11.373 回答
20

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

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

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

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

于 2011-08-08T13:05:30.897 回答
19

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){}
%>
于 2019-06-01T11:01:35.867 回答
16

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

于 2020-11-10T02:32:25.360 回答
15

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

await new Promise(resolve => setTimeout(resolve, 5000));
于 2019-11-19T13:34:36.653 回答
12

对于浏览器,我同意 setTimeout 和 setInterval 是要走的路。

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

如果您使用的是Node.jsMeteor,您可能会遇到在 Fiber 中使用 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 纤维、睡眠

于 2013-05-17T22:53:18.790 回答
12

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

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

在支持生成器和产量的较新的运行时中,可以为单线程环境中的 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 中使用。

于 2014-06-25T06:05:59.513 回答
12

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

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

它是这样使用的:

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

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

于 2015-07-09T13:59:21.790 回答
10

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

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

示例 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>
于 2009-11-10T04:22:27.983 回答
10

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);
    }
  }
于 2018-06-30T22:06:50.810 回答
9

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

于 2011-06-21T17:41:26.240 回答
9
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}
于 2013-11-09T18:37:54.373 回答
9

如果你想要比setTimeoutand更少笨重的函数setInterval,你可以将它们包装在函数中,这些函数只是颠倒参数的顺序并给它们起好听的名字:

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 毫秒,...”)

于 2015-01-04T04:41:17.707 回答
8

可以使用 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。

于 2013-01-14T01:32:07.647 回答
8

如果你在Node.js上,你可以看一下fibers ——node 的原生 C 扩展,一种多线程模拟。

它允许您以一种sleep在纤程中阻塞执行的方式进行真正的操作,但在主线程和其他纤程中是非阻塞的。

这是他们自己的自述文件中的一个新鲜示例:

// sleep.js

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 sleep.js
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
于 2015-02-06T10:55:38.977 回答
8

你可以做这样的事情。所有函数都可以继承的 sleep 方法:

Function.prototype.sleep = function(delay, ...args) {
    setTimeout(() => this(...args), delay)
}

console.log.sleep(2000, 'Hello, World!!')

于 2020-05-01T15:37:55.337 回答
7

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

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

于 2009-06-04T14:46:51.087 回答
7

对于想要分隔一组由循环执行的调用的特定情况,您可以使用类似于下面的代码的原型。如果没有原型,您可以将延迟函数替换为 setTimeout。

function itemHandler(item)
{
    alert(item);
}

var itemSet = ['a','b','c'];

// Each call to itemHandler will execute
// 1 second apart
for(var i=0; i<itemSet.length; i++)
{
    var secondsUntilExecution = i;
    itemHandler.delay(secondsUntilExecution, item)
}
于 2010-05-27T19:45:00.927 回答
7

您可能想要一个 sleep() 函数而不是使用 setTimeout() 的一种情况是,如果您有一个函数响应用户点击,最终将打开一个新的即弹出窗口,并且您已经启动了一些需要短时间的处理在弹出窗口显示之前完成。将打开的窗口移动到闭包中意味着它通常会被浏览器阻止。

于 2010-10-18T19:45:43.023 回答
6

2009 年的一个老问题。现在在 2015 年,使用 ECMAScript 2015 AKA ES6 中定义的生成器可以提供新的解决方案。它于 2015 年 6 月获得批准,但之前在 Firefox 和 Chrome 中实现。现在可以使 sleep 函数变得不忙、不阻塞并嵌套在循环和子函数中,而不会冻结浏览器。只需要纯 JavaScript - 不需要库或框架。

下面的程序显示了如何sleep()以及runSleepyTask()可以制作。该sleep()函数只是一个yield语句。它是如此简单,实际上yield直接编写语句而不是调用更容易sleep(),但是这样就不会有 sleep-word :-) yield 返回一个时间值给next()里面的方法wakeup()并等待。实际的“睡眠”是在wakeup()使用 good old 时完成的setTimeout()。在回调时,该next()方法触发yield语句继续,yield 的“魔力”是所有局部变量和它周围的整个调用堆栈仍然完好无损。

使用 sleep() 或 yield 的函数必须定义为生成器。通过在关键字中添加星号很容易做到这一点function*。执行生成器有点棘手。当使用关键字调用时,new生成器返回一个具有该next()方法的对象,但不执行生成器的主体(关键字new是可选的,没有区别)。该next()方法触发生成器主体的执行,直到遇到yield. 包装函数runSleepyTask()启动乒乓球:next()等待 a yield,然后yield等待 a next()

调用生成器的另一种方法是使用关键字yield*,在这里它的工作方式类似于简单的函数调用,但它还包括返回到的能力next()

这一切都在例子中得到了证明drawTree()。它在旋转的 3D 场景中绘制一棵带叶子的树。一棵树被画成树干,顶部有 3 个不同方向的部分。drawTree()然后通过在短暂的睡眠后递归调用,将每个部分绘制为另一棵较小的树。一棵很小的树被画成只有一片叶子。

每片叶子都有自己的生命,在一个单独的任务中开始runSleepyTask()。它出生、成长、坐落、消退、坠落和死亡growLeaf()。速度由 控制sleep()。这展示了多任务处理是多么容易。

function* sleep(milliseconds) {yield milliseconds};

function runSleepyTask(task) {
    (function wakeup() {
        var result = task.next();
        if (!result.done) setTimeout(wakeup, result.value);
    })()
}
//////////////// written by Ole Middelboe  /////////////////////////////

pen3D =setup3D();
var taskObject = new drawTree(pen3D.center, 5);
runSleepyTask(taskObject);

function* drawTree(root3D, size) {
    if (size < 2) runSleepyTask(new growLeaf(root3D))
    else {
        pen3D.drawTrunk(root3D, size);
        for (var p of [1, 3, 5]) {
            var part3D = new pen3D.Thing;
            root3D.add(part3D);
            part3D.move(size).turn(p).tilt(1-p/20);
            yield* sleep(50);
            yield* drawTree(part3D, (0.7+p/40)*size);
        }
    }
}

function* growLeaf(stem3D) {
    var leaf3D = pen3D.drawLeaf(stem3D);
    for (var s=0;s++<15;) {yield* sleep(100); leaf3D.scale.multiplyScalar(1.1)}
    yield* sleep( 1000 + 9000*Math.random() );
    for (var c=0;c++<30;) {yield* sleep(200); leaf3D.skin.color.setRGB(c/30, 1-c/40, 0)}
    for (var m=0;m++<90;) {yield* sleep( 50); leaf3D.turn(0.4).tilt(0.3).move(2)}
    leaf3D.visible = false;
}
///////////////////////////////////////////////////////////////////////

function setup3D() {
    var scene, camera, renderer, diretionalLight, pen3D;

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(75,
        window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 15, 20);
    renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    directionalLight = new THREE.DirectionalLight(0xffffaa, 0.7);
    directionalLight.position.set(-1, 2, 1);
    scene.add(directionalLight);
    scene.add(new THREE.AmbientLight(0x9999ff));

    (function render() {
        requestAnimationFrame(render);
        // renderer.setSize( window.innerWidth, window.innerHeight );
        scene.rotateY(10/60/60);
        renderer.render(scene, camera);
    })();

    window.addEventListener(
        'resize',
        function(){
            renderer.setSize( window.innerWidth, window.innerHeight );
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
       },
       false
    );

    pen3D = {
        drawTrunk: function(root, size) {
            // root.skin = skin(0.5, 0.3, 0.2);
            root.add(new THREE.Mesh(new THREE.CylinderGeometry(size/12, size/10, size, 16),
                root.skin).translateY(size/2));
            root.add(new THREE.Mesh(new THREE.SphereGeometry(size/12, 16),
                root.skin).translateY(size));
            return root;
        },

        drawLeaf: function(stem) {
            stem.skin.color.setRGB(0, 1, 0);
            stem.add(new THREE.Mesh(new THREE.CylinderGeometry(0, 0.02, 0.6),
                stem.skin) .rotateX(0.3).translateY(0.3));
            stem.add(new THREE.Mesh(new THREE.CircleGeometry(0.2),
                stem.skin) .rotateX(0.3).translateY(0.4));
            return stem;
        },

        Thing: function() {
            THREE.Object3D.call(this);
            this.skin = new THREE.MeshLambertMaterial({
                color: new THREE.Color(0.5, 0.3, 0.2),
                vertexColors: THREE.FaceColors,
                side: THREE.DoubleSide
            })
        }
    };

    pen3D.Thing.prototype = Object.create(THREE.Object3D.prototype);
    pen3D.Thing.prototype.tilt = pen3D.Thing.prototype.rotateX;
    pen3D.Thing.prototype.turn = pen3D.Thing.prototype.rotateY;
    pen3D.Thing.prototype.move = pen3D.Thing.prototype.translateY;

    pen3D.center = new pen3D.Thing;
    scene.add(pen3D.center);

    return pen3D;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>

3D 的东西隐藏在 setup3D() 中,只是为了使它比 console.log() 不那么无聊。顺便说一下,角度是用弧度测量的。

经测试可在 Firefox 和 Chrome 中运行。未在 Internet Explorer 和 iOS (iPad) 中实现。尝试自己运行它。

在我找到另一个答案之后,Gabriel Ratener 在一年前什么是 sleep() 的 JavaScript 版本做出了类似的回答?.

于 2015-10-10T00:43:07.910 回答
6

在 sleep 方法中,您可以返回任何 then-able 对象。不一定是新的承诺。

例子:

const sleep = (t) =>  ({ then: (r) => setTimeout(r, t) })

const someMethod = async () => {

    console.log("hi");
    await sleep(5000)
    console.log("bye");
}

someMethod()

于 2020-09-25T19:06:28.553 回答
4

首先 - setTimeout 和 setInterval 是应该使用的,因为 JavaScript 的回调性质。如果你想使用sleep()它是不正确的代码的控制流或架构。

话虽如此,我想我仍然可以帮助实现两次睡眠。

1.假装同步跑掉我的头顶:

// A module to do that //dual-license: MIT or WTF [you can use it anyhow and leave my nickname in a comment if you want to]
var _ = (function(){
  var queue = [];
  var play = function(){
    var go = queue.shift();
      if(go) {
        if(go.a) {
          go.f();
          play();
        }
        else
        {
          setTimeout(play, go.t);
        }
      }
  }
  return {
    go:function(f){
      queue.push({a:1, f:f});
    },
    sleep:function(t){
      queue.push({a:0, t:t});
    },
    playback:play
  }
})();

[也应该可以自动播放]

// Usage

_.go(function(){

  // Your code
  console.log('first');

});

_.sleep(5000);

_.go(function(){

  // Your code
  console.log('next');

});

// This triggers the simulation
_.playback();

2.真正的同步运行

有一天我想了很多,而我唯一想在 JavaScript 中真正入睡的想法是技术性的。

睡眠函数必须是一个同步Ajax 调用,其超时设置为睡眠值。这就是拥有真正的sleep().

于 2011-08-09T08:53:48.490 回答
4

从此链接获取的代码不会冻结计算机。但它仅适用于 Firefox。

/**
 * Netscape compatible WaitForDelay function.
 * You can use it as an alternative to Thread.Sleep() in any major programming language
 * that support it while JavaScript it self doesn't have any built-in function to do such a thing.
 * parameters:
 * (Number) delay in millisecond
 */
function nsWaitForDelay(delay) {
    /**
     * Just uncomment this code if you're building an extension for Firefox.
     * Since Firefox 3, we'll have to ask for user permission to execute XPCOM objects.
     */
    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

    // Get the current thread.
    var thread = Components.classes["@mozilla.org/thread-manager;1"].getService(Components.interfaces.nsIThreadManager).currentThread;

    // Create an inner property to be used later as a notifier.
    this.delayed = true;

    /* Call JavaScript setTimeout function
      * to execute this.delayed = false
      * after it finishes.
      */
    setTimeout("this.delayed = false;", delay);

    /**
     * Keep looping until this.delayed = false
     */
    while (this.delayed) {
        /**
         * This code will not freeze your browser as it's documented in here:
         * https://developer.mozilla.org/en/Code_snippets/Threads#Waiting_for_a_background_task_to_complete
         */
        thread.processNextEvent(true);
    }
}
于 2011-12-03T10:40:21.270 回答
4

如果你写一个这样的睡眠函数

var sleep = function(period, decision, callback){
    var interval = setInterval(function(){
        if (decision()) {
            interval = clearInterval(interval);
            callback();
        }
    }, period);
}

你有一个异步函数可以多次调用,

var xhr = function(url, callback){
    // Make an Ajax request
    // Call a callback when the request fulfils
}

你像这样设置你的项目:

var ready = false;

function xhr1(){
    xhr(url1, function(){ ready = true;});
}
function xhr2(){
    xhr(url2, function(){ ready = true; });
}
function xhr3(){
    xhr(url3, function(){ ready = true; });
}

然后你可以这样做:

xhr1();
sleep(100, function(){ return done; }, xhr2);
sleep(100, function(){ return done; }, xhr3);
sleep(100, function(){ return done; }, function(){
    // Do more
});

而不是像这样无休止的回调缩进:

xhr(url1, function(){
    xhr2(url2, function(){
        xhr3(url3, function(){
            // Do more
        });
    });
});
于 2013-07-29T21:20:11.637 回答
3

我需要一个忙碌的等待来进行测试。我不想拆分代码,因为那会是很多工作,所以一个简单的 for为我做了。

for (var i=0; i<1000000; i++){                  
    // Waiting
}

我没有看到这样做有任何不利之处,它对我有用。

于 2012-12-20T11:57:30.730 回答
3

如果你真的需要一个 sleep() 来测试一些东西。但是请注意,它在调试时大部分时间都会使浏览器崩溃——这可能就是你需要它的原因。在生产模式下,我将注释掉这个函数。

function pauseBrowser(millis) {
    var date = Date.now();
    var curDate = null;
    do {
        curDate = Date.now();
    } while (curDate-date < millis);
}

不要在循环中使用 new Date() ,除非您想浪费内存、处理能力、电池以及可能的设备寿命。

于 2015-01-09T22:17:48.023 回答
3

我更喜欢这种功能风格 的单线 sleep功能:

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

// usage
async function main() {
  console.log("before");
  const t = await sleep(10_000); /* 10 sec */
  console.log("after " + t);
}
main();
于 2019-01-11T11:00:23.540 回答
2

这真的不是一个好主意。这样做会导致整个页面在系统等待您的函数返回时冻结。

于 2009-06-04T14:48:57.603 回答
2

您可以使用具有递增值的闭包调用 setTimeout()。

var items = ['item1', 'item2', 'item3'];

function functionToExecute(item) {
  console.log('function executed for item: ' + item);
}

$.each(items, function (index, item) {
  var timeoutValue = index * 2000;
  setTimeout(function() {
    console.log('waited ' + timeoutValue + ' milliseconds');
    functionToExecute(item);
  }, timeoutValue);
});

结果:

waited 0 milliseconds
function executed for item: item1
waited 2000 milliseconds
function executed for item: item2
waited 4000 milliseconds
function executed for item: item3
于 2014-04-28T17:30:58.543 回答
2

如果您喜欢建议不要失去性能。setTimeout是你的预期sleep。但是,如果您想要代码被“除以”的语法sleep,我们可以这样做:

sleep = function(tm, fn){
   window.setTimeout(fn, tm);
}

然后,准备如下函数:

var fnBeforeSleep = function(){

  // All code before sleep

}

var fnAfterSleep = function(){

  // All code after sleep

}

然后:

fnBeforeSleep();
sleep(2000, fnAfterSleep);

// Yep! Syntactically, it is very close to:

fnBeforeSleep();
sleep(2000);
fnAfterSleep();
于 2014-06-04T20:41:26.197 回答
2

拥抱 JavaScript 的异步特性!

以下所有内容都将立即返回,但只有一个地方可以放置您想要在发生某些事情后运行的代码。

我在这里概述的方法都适用于不同的用例,并且根据它们的复杂性进行了粗略排序。

不同之处如下:

  • 等待某个条件变为真
  • 在调用单个回调之前等待一组方法完成(以任何顺序)
  • 在调用回调之前以特定顺序运行一系列具有共享状态的异步方法

等待

在没有任何可访问的回调告诉您某事何时完成执行的情况下,等待查看某个条件是否为真很有用。

这是一个非常基本的实现,它假设条件将在某个时候变为真。通过一些调整,它可以扩展为更加有用(例如,通过设置调用限制)。(我昨天才写了这个!)

function waitFor(predicate, successCallback) {
    setTimeout(function () {
        var result = predicate();
        if (result !== undefined)
            successCallback(result);
        else
            waitFor(predicate, successCallback);
    }, 100);
}

调用代码:

beforeEach(function (done) {
    selectListField('A field');

    waitFor(function () {
        var availableOptions = stores.scrapeStore(optionStore);
        if (availableOptions.length !== 0)
            return availableOptions;
    }, done);
});

在这里,我调用了一个加载Ext JS 'store' 的东西,并等到 store 包含一些东西,然后再继续(beforeEachJasmine测试框架的东西)。

等待几件事完成

在完成不同方法的加载后,我还需要运行一个回调。你可以这样做:

createWaitRunner = function (completionCallback) {
    var callback = completionCallback;
    var completionRecord = [];
    var elements = 0;

    function maybeFinish() {
        var done = completionRecord.every(function (element) {
            return element === true
        });

        if (done)
            callback();
    }

    return {
        getNotifier: function (func) {
            func = func || function (){};

            var index = elements++;
            completionRecord[index] = false;

            return function () {
                func.applyTo(arguments);
                completionRecord[index] = true;
                maybeFinish();
            }
        }
    }
};

调用代码:

var waiter = createWaitRunner(done);

filterList.bindStore = waiter.getNotifier();
includeGrid.reconfigure = waiter.getNotifier(function (store) {
    includeStore = store;
});

excludeGrid.reconfigure = waiter.getNotifier(function (store) {
    excludeStore = store;
});

您要么只是等待通知,要么也可以包装使用传递给函数的值的其他函数。当调用所有方法时,done将运行。

按顺序运行异步方法

当我有一系列异步方法连续调用时(再次在测试中),我使用了不同的方法。这有点类似于你可以在Async 库中获得的东西——series做了同样的事情,我首先阅读了那个库,看看它是否符合我的要求。我认为我有一个更好的 API 来处理测试(而且实现起来很有趣!)。

// Provides a context for running asynchronous methods synchronously
// The context just provides a way of sharing bits of state
// Use 'run' to execute the methods.  These should be methods that take a callback and optionally the context as arguments
// Note the callback is provided first, so you have the option of just partially applying your function to the arguments you want
// instead of having to wrap even simple functions in another function

// When adding steps you can supply either just a function or a variable name and a function
// If you supply a variable name then the output of the function (which should be passed into the callback) will be written to the context
createSynchronisedRunner = function (doneFunction) {
    var context = {};

    var currentPosition = 0;
    var steps = [];

    // This is the loop. It is triggered again when each method finishes
    var runNext = function () {
        var step = steps[currentPosition];
        step.func.call(null,
                       function (output) {
                           step.outputHandler(output);
                           currentPosition++;

                           if (currentPosition === steps.length)
                               return;

                           runNext();
                       }, context);
    };

    var api = {};

    api.addStep = function (firstArg, secondArg) {
        var assignOutput;
        var func;

        // Overloads
        if (secondArg === undefined) {
            assignOutput = function () {
            };
            func = firstArg;
        }
        else {
            var propertyName = firstArg;
            assignOutput = function (output) {
                context[propertyName] = output;
            };
            func = secondArg;
        }

        steps.push({
            func: func,
            outputHandler: assignOutput
        });
    };

    api.run = function (completedAllCallback) {
        completedAllCallback = completedAllCallback || function(){};

        var lastStep = steps[steps.length - 1];
        var currentHandler = lastStep.outputHandler;
        lastStep.outputHandler = function (output) {
            currentHandler(output);
            completedAllCallback(context);
            doneFunction();
        };

        runNext();
    };

    // This is to support more flexible use where you use a done function in a different scope to initialisation
    // For example, the done of a test but create in a beforeEach
    api.setDoneCallback = function (done) {
        doneFunction = done;
    };

    return api;
};

调用代码:

beforeAll(function (done) {
    var runner = createSynchronisedRunner(done);
    runner.addStep('attachmentInformation', testEventService.getAttachmentCalled.partiallyApplyTo('cat eating lots of memory.jpg'));
    runner.addStep('attachment', getAttachment.partiallyApplyTo("cat eating lots of memory.jpg"));
    runner.addStep('noAttachment', getAttachment.partiallyApplyTo("somethingElse.jpg"));
    runner.run(function (context) {
        attachment = context.attachment;
        noAttachment = context.noAttachment;
    });
});

这里的PartiallyApplyTo基本上是Douglas Crockford的 Curry 实现的重命名版本。我正在使用的很多东西都将回调作为最终参数,因此可以像这样完成简单的调用,而不必用额外的函数包装所有内容。

于 2014-08-05T09:35:54.283 回答
2

我知道问题是关于睡眠的,很明显答案是不可能的。我认为睡眠的一个共同需求是按顺序处理异步任务;我知道我必须肯定地处理它。

很多情况下它可能可以使用promises(Ajax请求常用)。它们让你以同步的方式做异步的事情。还有成功/失败的处理,它们可以被链接起来。

它们是 ECMAScript 6 的一部分,因此浏览器支持还不是全部,主要是 Internet Explorer 不支持它们。还有一个叫做 Q 的库来做承诺。

参考:

于 2015-01-22T18:19:22.363 回答
2

有了await支持和蓝鸟承诺

await bluebird.delay(1000);

这将像C 语言sleep(1)的同步一样工作。我最喜欢的解决方案。

于 2016-08-29T10:26:53.663 回答
2

这将为您解决问题。

var reloadAfter = 10; //seconds
var intervalId = setTimeout(function() {
    //code you want to execute after the time waiting
}, reloadAfter * 1000); // 60000 = 60 sec = 1 min
于 2016-12-22T09:51:47.883 回答
2

一个休眠的函数,使用同步调用让操作系统来做。使用您喜欢的任何操作系统睡眠命令。从使用 CPU 时间的意义上说,它不是忙于等待。

我选择 ping 一个不存在的地址。

const cp = require('child_process');

function sleep(ms)
{
    try{cp.execSync('ping 192.0.2.0 -n 1 -w '+ms);}
    catch(err){}
}

验证它是否有效的测试

console.log(Date.now());
console.log(Date.now());
sleep(10000);
console.log(Date.now());
console.log(Date.now());

以及一些测试结果。

1491575275136
1491575275157

(10秒后)

1491575285075
1491575285076
于 2017-04-07T14:39:36.487 回答
2

如果您想要可在所有浏览器上使用的代码,请使用setTimeout()and clearTimeout()。如果您正在阅读这么多的答案,您可能会注意到接受的答案会破坏Internet Explorer 11中的所有 JavaScript 编译,并且在使用此解决方案后,似乎大约 5% 的用户仍在使用这个积极开发的浏览器和需要支持。

这几乎破坏了一切。已知有关于箭头函数破坏了DrupalWordPressAmazon AWSIBM软件的 Internet Explorer 11 功能的报道,甚至在 Stack Overflow 上也有专门的讨论

只是检查一下...

浏览器兼容性图表 - 箭头函数表达式

浏览器兼容性图表 - setTimeout

使用setTimeout()and clearTimeout(),这将适用于所有浏览器......

工作 JSBin 演示

var timeout;

function sleep(delay) {
    if(timeout) {
        clearTimeout(timeout);
    }
    timeout = setTimeout(function() {
        myFunction();
    }, delay);
}

console.log("sleep for 1 second");
sleep(1000);

function myFunction() {
    console.log("slept for 1 second!");
}

于 2021-02-09T22:19:17.013 回答
2

这是睡眠的阻塞版本。发现在需要顺序执行的测试活动中更容易遵循。它可以被称为sleep(2000)让线程休眠 2 秒。

function sleep(ms) {
    const now = Date.now();
    const limit = now + ms;
    let execute = true;
    while (execute) {
        if (limit < Date.now()) {
            execute = false;
        }
    }
    return;
  }
于 2021-12-04T14:59:52.567 回答
2

天真地,您可以sleep()使用与 pausecomp 函数相同的 while 循环来实现(这基本相同):

const sleep = (seconds) => {
    const waitUntil = new Date().getTime() + seconds * 1000
    while(new Date().getTime() < waitUntil) {
        // do nothing
    }
}

你可以使用这样的sleep()方法:

const main = () => {
    const a = 1 + 3

    // Sleep 3 seconds before the next action
    sleep(3)
    const b = a + 4

    // Sleep 4 seconds before the next action
    sleep(4)
    const c = b + 5
}

main()

这就是我想象你会使用 sleep 功能的方式,并且阅读起来相对简单。我借用了另一篇文章Sleep in JavaScript - delay between actions来展示你可能打算如何使用它。

不幸的是,您的计算机会变热,所有工作都将被阻止。如果在浏览器中运行,选项卡将停止,用户将无法与页面交互。

如果您将代码重组为异步,那么您可以利用setTimeout()作为与其他帖子相同的睡眠功能。

// define sleep using setTimeout
const sleep = (seconds, callback) => setTimeout(() => callback(), seconds * 1000)

const main = () => {
    const a = 1 + 3
    let b = undefined
    let c = undefined

    // Sleep 3 seconds before the next action
    sleep(3, () => {
        b = a + 4

        // Sleep 4 seconds before the next action
        sleep(4, () => {
            c = b + 5
        })
    })
}

main()

正如你所说,这不是你想要的。我修改了来自JavaScript 中的睡眠的示例 - 动作之间的延迟,以说明为什么会这样。当您添加更多操作时,您要么需要将逻辑拉入单独的函数中,要么将代码嵌套得越来越深(回调地狱)。

为了解决“回调地狱”,我们可以使用Promise来定义 sleep :

const sleep = (seconds) => new Promise((resolve => setTimeout(() => resolve(), seconds * 1000)))

const main = () => {
    const a = 1 + 3
    let b = undefined
    let c = undefined

    // Sleep 3 seconds before the next action
    return sleep(3)
        .then(() => {
            b = a + 4

            // Sleep 4 seconds before the next action
            return sleep(4)
        })
        .then(() => {
            c = b + 5
        })
}

main()

Promise 可以避免深度嵌套,但仍然不像我们开始使用的常规同步代码。我们想要编写看起来是同步的,但没有任何缺点的代码。

让我们再次使用async/await重写我们的 main 方法:

const sleep = (seconds) => new Promise((resolve => setTimeout(() => resolve(), seconds * 1000)))

const main = async () => {
    const a = 1 + 3

    // Sleep 3 seconds before the next action
    await sleep(3)
    const b = a + 4

    // Sleep 4 seconds before the next action
    await sleep(4)
    const c = b + 5
}

main()

使用 async/await,我们sleep()几乎可以调用它,就好像它是一个同步的阻塞函数。这解决了您在其他帖子中的回调解决方案可能遇到的问题,并避免了长时间运行的循环问题。

于 2022-01-26T18:39:08.860 回答
1

如果你想休眠一个匿名函数,比如你作为处理程序创建的函数,我建议如下:

function()
{
    if (!wait_condition)
    {
        setTimeout(arguments.callee, 100, /* Comma-separated arguments here */);
    }
    // The rest of the function
}

此代码显示“如果尚未满足等待条件,请使用这些参数再次调用此函数。” 我已使用此方法将相同的参数传递给我的处理程序,从而有效地使此代码成为非轮询 sleep() (仅在函数开始时有效)。

于 2011-09-26T19:51:33.033 回答
1

需要使用“睡眠”方法的对象的方法,例如:

function SomeObject() {
    this.SomeProperty = "xxx";
    return this;
}
SomeObject.prototype.SomeMethod = function () {
    this.DoSomething1(arg1);
    sleep(500);
    this.DoSomething2(arg1);
}

几乎可以翻译成:

function SomeObject() {
    this.SomeProperty = "xxx";
    return this;
}
SomeObject.prototype.SomeMethod = function (arg1) {
    var self = this;
    self.DoSomething1(arg1);
    setTimeout(function () {
        self.DoSomething2(arg1);
    }, 500);
}

不同之处在于“SomeMethod”的操作在“DoSomething2”操作执行之前返回。“SomeMethod”的调用者不能依赖于此。由于“睡眠”方法不存在,我使用后一种方法并相应地设计我的代码。

于 2012-02-13T22:50:42.997 回答
1

有一个新的库,Sequencr.js,它巧妙地将函数与超时链接在一起,这样你就可以避免回调地狱。

它变成了这样:

setTimeout(function(timeout){
    function1();
    setTimeout(function(timeout){
        function2();
        setTimeout(function(timeout){
            function3();
        }, timeout, timeout)
    }, timeout, timeout)
}, 10, 10);

进入这个:

Sequencr.chain([function1, function2, function3], 10);

并且内置了对在每次迭代之间“休眠”的循环的支持。

于 2016-03-09T10:06:43.923 回答
1

这里大多数解决方案的问题是它们倒回堆栈。在某些情况下,这可能是一个大问题。在这个例子中,我展示了如何以不同的方式使用迭代器来模拟真正的 sleep

在这个例子中,生成器正在调用它自己的next(),所以一旦它开始运行,它就是独立的。

var h = a();
h.next().value.r = h; // That's how you run it. It is the best I came up with

// Sleep without breaking the stack!!!
function *a(){
    var obj = {};

    console.log("going to sleep....2s")

    setTimeout(function(){obj.r.next();}, 2000)
    yield obj;

    console.log("woke up");
    console.log("going to sleep no 2....2s")
    setTimeout(function(){obj.r.next();}, 2000)
    yield obj;

    console.log("woke up");
    console.log("going to sleep no 3....2s")

    setTimeout(function(){obj.r.next();}, 2000)
    yield obj;

    console.log("done");
}
于 2016-10-13T14:31:04.117 回答
1

保持主线程忙碌几毫秒:

function wait(ms) {
  const start = performance.now();
  while(performance.now() - start < ms);
}
于 2017-09-27T21:34:38.413 回答
1

如果您真的想完全阻塞主线程并阻止事件循环从事件队列中拉出,这里有一个很好的方法来做到这一点,而无需创建任何函数、新的 Date 对象或泄漏任何变量。我知道这个愚蠢的问题已经有一百万个答案,但我没有看到有人使用这个确切的解决方案。这仅适用于现代浏览器。

警告:这不是你永远不会投入生产的东西。它只是有助于理解浏览器事件循环。它甚至可能对任何测试都没有用。它不像普通的系统睡眠功能,因为 JavaScript 运行时仍然在每个周期都在工作。

for (let e = performance.now() + 2000; performance.now() < e; ) {}

在这里使用时,即使它几乎立即进入事件队列,至少两秒后才会调用 setTimeout 回调:

setTimeout(function() {
  console.log("timeout finished");
}, 0);

for (let e = performance.now() + 2000; performance.now() < e; ) {}
console.log("haha wait for me first");

您将经历大约两秒钟的停顿,然后看到:

haha wait for me first
timeout finished

使用 performance.now() 而不是 Date.now() 的好处是 Date 对象是

受时钟偏差和系统时钟的调整。时间值可能并不总是单调增加,后续值可能会减少或保持不变。 *

一般来说,performance.now() 更适合以高精度测量时间差异。

使用for循环的好处是可以让您在运行之前将变量设置为块的本地变量。这使您可以在循环之外进行加法​​运算,同时仍然是“单线”。这应该有望最大限度地减少这种热循环烧伤的 CPU 负载。

于 2020-02-21T01:38:23.337 回答
1

使用打字稿:

sleep()这是一个可以等待的快速实现。这与最佳答案尽可能相似。它在功能上是等价的,除了ms类型与numberTypeScript 相同。

const sleep = (ms: number) =>
  new Promise((resolve) => setTimeout(resolve, ms));

async function demo() {
  console.log('Taking a break for 2s (2000ms)...');
  await sleep(2000);
  console.log('Two seconds later');
}

demo();

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

注意,

  1. await只能在以async关键字为前缀的函数中执行,或者在某些环境(例如,Chrome DevTools 控制台或 Runkit)中脚本的顶层执行。
  2. await仅暂停当前async功能。
于 2020-03-04T16:51:43.530 回答
1

sleep() 的 JavaScript 版本是什么?

这已经在当前接受的答案中得到了回答

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

两个异步函数同时运行

把它放在一个函数中是个好主意sleep(),然后 await sleep().
要使用它,需要一些上下文:

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

(async function slowDemo () {
  console.log('Starting slowDemo ...');
  await sleep(2000);
  console.log('slowDemo: TWO seconds later ...');
})();

(async function fastDemo () {
  console.log('Starting fastDemo ...');
  await sleep(500);
  for (let i = 1; i < 6; i++) {
    console.log('fastDemo: ' + (i * 0.5) + ' seconds later ...');
    await sleep(500);
  }
})();
.as-console-wrapper { max-height: 100% !important; top: 0; }

两个按顺序运行的异步调用——一个接一个

但是假设slowDemo产生一些fastDemo 取决于的结果。
在这种情况下,slowDemo必须在开始之前运行完成fastDemo

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

(async () => {
  await (async function slowDemo () {
    console.log('Starting slowDemo ...');
    await sleep(2000);
    console.log('slowDemo: TWO seconds later ... completed!');
  })();

  (async function fastDemo () {
    console.log('Starting fastDemo ...');
    await sleep(500);
    let i = -2;
    for (i = 1; i < 5; i++) {
      console.log('fastDemo: ' + (i * 0.5) + ' seconds later ...');
      await sleep(500);
    }
    console.log('fastDemo: ' + (i * 0.5) + ' seconds later. Completed!');
  })();
})();
.as-console-wrapper { max-height: 100% !important; top: 0; }

于 2021-05-25T16:28:49.523 回答
0

在某些情况下,一个不错的选择是显示一个顶级消息面板来停止用户交互,然后在获得等待的结果时再次隐藏它(异步)。这允许浏览器继续执行后台任务,但会暂停工作流程,直到您获得结果。

于 2012-11-01T11:56:48.407 回答
0

简短的回答是否定的,不是 JavaScript 本身。您的解决方案似乎是不将控制权返回给环境的唯一方法。

如果环境不支持事件,这是必要的。他们可能也不支持setTimeout

如果您处于事件驱动的环境(例如浏览器或Node.js )中, setTimeout绝对是最好的方法。

于 2013-10-31T19:08:49.523 回答
0

我确信有一百万种方法可以更好地做到这一点,但我想我会通过创建一个对象来尝试一下:

// execute code consecutively with delays (blocking/non-blocking internally)
function timed_functions()
{
    this.myfuncs = [];
    this.myfuncs_delays = []; // mirrors keys of myfuncs -- values stored are custom delays, or -1 for use default
    this.myfuncs_count = 0; // increment by 1 whenever we add a function
    this.myfuncs_prev    = -1; // previous index in array
    this.myfuncs_cur    = 0; // current index in array
    this.myfuncs_next  = 0; // next index in array
    this.delay_cur     = 0; // current delay in ms
    this.delay_default = 0; // default delay in ms
    this.loop = false;      // will this object continue to execute when at end of myfuncs array?
    this.finished = false;  // are we there yet?
    this.blocking = true;   // wait till code completes before firing timer?
    this.destroy = false;   // <advanced> destroy self when finished


    this.next_cycle = function() {
        var that  = this;
        var mytimer = this.delay_default;

        if(this.myfuncs_cur > -1)
            if(this.myfuncs_delays[this.myfuncs_cur] > -1)
                mytimer = this.myfuncs_delays[this.myfuncs_cur];

        console.log("fnc:" + this.myfuncs_cur);
        console.log("timer:" + mytimer);
        console.log("custom delay:" + this.myfuncs_delays[this.myfuncs_cur]);
        setTimeout(function() {
        // Time is up! Next cycle...
        that.cycle();

    }, mytimer);
}

this.cycle = function() {

    // Now check how far we are along our queue.. is this the last function?
    if(this.myfuncs_next + 1 > this.myfuncs_count)
    {
        if(this.loop)
        {
            console.log('looping..');
            this.myfuncs_next = 0;
        }
        else
            this.finished = true;
    }

    // First check if object isn't finished
    if(this.finished)
        return false;

    // HANDLE NON BLOCKING //
    if(this.blocking != true) // Blocking disabled
    {
        console.log("NOT BLOCKING");
        this.next_cycle();
    }

    // Set prev = current, and current to next, and next to new next
    this.myfuncs_prev = this.myfuncs_cur;
    this.myfuncs_cur  = this.myfuncs_next;
    this.myfuncs_next++;

    // Execute current slot
    this.myfuncs[this.myfuncs_cur]();

    // HANDLE BLOCKING
    if(this.blocking == true)  // Blocking enabled
    {
        console.log("BLOCKING");
        this.next_cycle();
    }

    return true;
};

// Adders
this.add = {
    that:this,

    fnc: function(aFunction) {
        // Add to the function array
        var cur_key = this.that.myfuncs_count++;
        this.that.myfuncs[cur_key] = aFunction;
        // Add to the delay reference array
        this.that.myfuncs_delays[cur_key] = -1;
    }
}; // end::this.add

// setters
this.set = {
    that:this,

    delay: function(ms) {
        var cur_key = this.that.myfuncs_count - 1;
        // This will handle the custom delay array this.that.myfunc_delays
        // Add a custom delay to your function container

        console.log("setting custom delay. key: "+ cur_key + " msecs: " + ms);
        if(cur_key > -1)
        {
            this.that.myfuncs_delays[cur_key] = ms;
        }
        // So now we create an entry on the delay variable
    },

    delay_cur:      function(ms) { this.that.delay_cur = ms; },
    delay_default:  function(ms) { this.that.delay_default = ms; },
    loop_on:        function()   { this.that.loop = true; },
    loop_off:       function()   { this.that.loop = false; },
    blocking_on:    function()   { this.that.blocking = true; },
    blocking_off:   function()   { this.that.blocking = false; },

    finished:            function(aBool) { this.that.finished = true; }
}; // end::this.set


// Setters
this.get = {
    that:this,

    delay_default: function() { return this.that.delay_default; },
    delay_cur:     function() { return this.that.delay_cur; }
    }; // end::this.get

} // end:::function timed_functions()

并像这样使用它:

// // // BEGIN :: TEST // // //

// Initialize
var fncTimer = new timed_functions;

// Set some defaults
fncTimer.set.delay_default(1000);
fncTimer.set.blocking_on();
// fncTimer.set.loop_on();
// fncTimer.set.loop_off();


// BEGIN :: ADD FUNCTIONS (they will fire off in order)
fncTimer.add.fnc(function() {
    console.log('plan a (2 secs)');
});
fncTimer.set.delay(2000); // Set a custom delay for previously added function

fncTimer.add.fnc(function() {
    console.log('hello world (delay 3 seconds)');
});
fncTimer.set.delay(3000);

fncTimer.add.fnc(function() {
    console.log('wait 4 seconds...');
});
fncTimer.set.delay(4000);

fncTimer.add.fnc(function() {
    console.log('wait 2 seconds');
});
fncTimer.set.delay(2000);

fncTimer.add.fnc(function() {
    console.log('finished.');
});
// END :: ADD FUNCTIONS


// NOW RUN
fncTimer.cycle(); // Begin execution


// // // END :: TEST // // //
于 2014-03-12T01:11:43.060 回答
0

总结一下(就像以前的答案中所说的那样):

JavaScript 中没有内置的睡眠功能。您应该使用setTimeoutsetInterval来实现类似的效果。

如果您真的想这样做,您可以使用for循环来模拟睡眠功能,例如原始问题中显示的循环,但这会使您的 CPU 疯狂工作。在 Web Worker 内部,另一种解决方案是同步XMLHttpRequest到无响应的 IP 地址并设置适当的超时。这将避免 CPU 利用率问题。这是一个代码示例:

// Works only inside a web worker

function sleep(milliseconds) {
    var req = new XMLHttpRequest();
    req.open("GET", "http://192.0.2.0/", false);
    req.timeout = milliseconds;
    try {
        req.send();
    } catch (ex) {

    }
}

console.log('Sleeping for 1 second...');
sleep(1000);
console.log('Slept!');

console.log('Sleeping for 5 seconds...')
sleep(5000);
console.log('Slept!');

于 2015-09-01T04:34:39.663 回答
0

我浏览了一天的解决方案,但我仍在考虑如何在使用回调时保持可链接性。

每个人都熟悉以同步方式逐行运行代码的传统编程风格。SetTimeout 使用回调,因此下一行不会等待它完成。这让我想到了如何让它“同步”,从而实现“睡眠”功能。

从一个简单的协程开始:

function coroutine() {
    console.log('coroutine-1:start');
    sleepFor(3000); // Sleep for 3 seconds here
    console.log('coroutine-2:complete');
}

中间想睡3秒,但又不想主宰整个流程,所以协程必须由另一个线程执行。我考虑Unity YieldInstruction,并在下面修改协程:

function coroutine1() {
    this.a = 100;
    console.log('coroutine1-1:start');
    return sleepFor(3000).yield; // Sleep for 3 seconds here
    console.log('coroutine1-2:complete');
    this.a++;
}

var c1 = new coroutine1();

声明 sleepFor 原型:

sleepFor = function(ms) {
    var caller = arguments.callee.caller.toString();
    var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];
    var args = arguments.callee.caller.arguments;
    var funcBody = caller.replace(/^[\s\S]*?sleepFor[\s\S]*?yield;|}[\s;]*$/g,'');
    var context = this;
    setTimeout(function() {
        new Function(funcArgs, funcBody).apply(context, args);
    }, ms);
    return this;
}

运行 coroutine1(我在 Internet Explorer 11 和 Chrome 49 中测试过)后,您会看到它在两个控制台语句之间休眠 3 秒。它使代码与传统风格一样漂亮。

棘手的一点是在 sleepFor 例程中。它将调用者函数体读取为字符串并将其分成两部分。移除上部并通过下部创建另一个功能。在等待指定的毫秒数后,它通过应用原始上下文和参数来调用创建的函数。对于原始流程,它将像往常一样以“返回”结束。为了“收益”?它用于正则表达式匹配。这是必要的,但根本没有用。

它根本不是 100% 完美,但它至少完成了我的工作。我不得不提到使用这段代码的一些限制。由于代码被分成两部分,“return”语句必须在外部,而不是在任何循环或 {} 中。IE

function coroutine3() {
    this.a = 100;
    console.log('coroutine3-1:start');
    if(true) {
        return sleepFor(3000).yield;
    } // <- Raise an exception here
    console.log('coroutine3-2:complete');
    this.a++;
}

上面的代码一定有问题,因为在创建的函数中不能单独存在右括号。另一个限制是“var xxx=123”声明的所有局部变量都不能传递到下一个函数。您必须使用“this.xxx=123”来实现相同的目的。如果您的函数有参数并且它们发生了更改,则修改后的值也无法传递到下一个函数。

function coroutine4(x) { // Assume x=abc
    var z = x;
    x = 'def';
    console.log('coroutine4-1:start' + z + x); // z=abc, x=def
    return sleepFor(3000).yield;
    console.log('coroutine4-2:' + z + x); // z=undefined, x=abc
}

我将介绍另一个函数原型:waitFor

waitFor = function(check, ms) {
    var caller = arguments.callee.caller.toString();
    var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];
    var args = arguments.callee.caller.arguments;
    var funcBody = caller.replace(/^[\s\S]*?waitFor[\s\S]*?yield;|}[\s;]*$/g,'');
    var context = this;
    var thread = setInterval(function() {
        if(check()) {
            clearInterval(thread);
            new Function(funcArgs, funcBody).apply(context, args);
        }
    }, ms?ms:100);
    return this;
}

它等待“检查”功能,直到它返回真。它每 100 毫秒检查一次值。您可以通过传递附加参数来调整它。考虑测试协程2:

function coroutine2(c) {
    /* Some code here */
    this.a = 1;
    console.log('coroutine2-1:' + this.a++);
    return sleepFor(500).yield;

    /* Next */
    console.log('coroutine2-2:' + this.a++);
    console.log('coroutine2-2:waitFor c.a>100:' + c.a);
    return waitFor(function() {
        return c.a>100;
    }).yield;

    /* The rest of the code */
    console.log('coroutine2-3:' + this.a++);
}

也是迄今为止我们喜欢的漂亮风格。其实我讨厌嵌套回调。很容易理解,coroutine2 会等待 coroutine1 完成。有趣的?好的,然后运行以下代码:

this.a = 10;
console.log('outer-1:' + this.a++);
var c1 = new coroutine1();
var c2 = new coroutine2(c1);
console.log('outer-2:' + this.a++);

输出是:

outer-1:10
coroutine1-1:start
coroutine2-1:1
outer-2:11
coroutine2-2:2
coroutine2-2:waitFor c.a>100:100
coroutine1-2:complete
coroutine2-3:3

初始化 coroutine1 和 coroutine2 后立即完成 Outer。然后,coroutine1 将等待 3000 毫秒。Coroutine2 等待 500 毫秒后进入第 2 步。之后,一旦检测到 coroutine1.a 值 > 100,它将继续第 3 步。

请注意,存在三个上下文来保存变量“a”。一个是outer,取值是10和11。另外一个在coroutine1里面,取值是100和101。最后一个在coroutine2里面,取值是1,2和3。在coroutine2里面,也是在等待ca的到来从 coroutine1,直到它的值大于 100。3 个上下文是独立的。

复制和粘贴的整个代码:

sleepFor = function(ms) {
    var caller = arguments.callee.caller.toString();
    var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];
    var args = arguments.callee.caller.arguments;
    var funcBody = caller.replace(/^[\s\S]*?sleepFor[\s\S]*?yield;|}[\s;]*$/g,'');
    var context = this;
    setTimeout(function() {
        new Function(funcArgs, funcBody).apply(context, args);
    }, ms);
    return this;
}

waitFor = function(check, ms) {
    var caller = arguments.callee.caller.toString();
    var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];
    var args = arguments.callee.caller.arguments;
    var funcBody = caller.replace(/^[\s\S]*?waitFor[\s\S]*?yield;|}[\s;]*$/g,'');
    var context = this;
    var thread = setInterval(function() {
        if(check()) {
            clearInterval(thread);
            new Function(funcArgs, funcBody).apply(context, args);
        }
    }, ms?ms:100);
    return this;
}

function coroutine1() {
    this.a = 100;
    console.log('coroutine1-1:start');
    return sleepFor(3000).yield;
    console.log('coroutine1-2:complete');
    this.a++;
}

function coroutine2(c) {
    /* Some code here */
    this.a = 1;
    console.log('coroutine2-1:' + this.a++);
    return sleepFor(500).yield;

    /* next */
    console.log('coroutine2-2:' + this.a++);
    console.log('coroutine2-2:waitFor c.a>100:' + c.a);
    return waitFor(function() {
        return c.a>100;
    }).yield;

    /* The rest of the code */
    console.log('coroutine2-3:' + this.a++);
}

this.a = 10;
console.log('outer-1:' + this.a++);
var c1 = new coroutine1();
var c2 = new coroutine2(c1);
console.log('outer-2:' + this.a++);

它在 Internet Explorer 11 和 Chrome 49 中进行了测试。因为它使用arguments.callee,所以如果它在严格模式下运行可能会很麻烦。

于 2016-03-28T01:04:34.713 回答
0

如果你真的想暂停一个脚本,你可以这样做:

var milliseconds;
var pretime;
var stage;

function step(time){
  switch(stage){
    case 0:
      //Code before the pause

      pretime=time;
      milliseconds=XXX;
      stage=1;
      break;
    case 1:
      //Code that is looped through while paused

      if(time-pretime >= milliseconds){
        //Code after the pause

        pretime=time;
        milliseconds=XXX;
        stage=2;
      }
      break;
    case 2:
      //Code that is looped through while paused

      if(time-pretime >= milliseconds){
        //Code after the pause

        pretime=time;
        milliseconds=XXX;
        stage=3;
      }
      break;
    case 3:
      //Etc...
  }

  Window.requestAnimationFrame(step)
}

step();

如果您仍然使用循环,这可能正是您想要的,并且您可以通过一些方式对其进行更改,以便您拥有伪多线程,其中您有一些函数等待一段时间而其他函数正常运行。我一直将它用于纯 JavaScript 游戏。

于 2016-03-31T20:10:35.087 回答
0

在服务器端,您可以使用deasync sleep()方法,该方法在C中原生实现,因此它可以有效地实现等待效果,而不会阻塞事件循环或将 CPU 置于 100% 负载。

例子:

#!/usr/bin/env node

// Requires `npm install --save deasync`
var sleep = require("deasync").sleep;

sleep(5000);

console.log ("Hello World!!");

但是,如果您需要一个JavaScript 函数(例如,通过浏览器在客户端运行它),我很抱歉地说我认为您的pausecomp()函数是实现它的唯一方法,而且不仅如此:

  1. 这不仅会暂停您的功能,还会暂停整个事件循环。所以不会参加其他活动。

  2. 它使您的 CPU 处于 100% 负载。

所以,如果你需要它作为浏览器脚本并且不想要那些可怕的效果,我必须说你应该以某种方式重新考虑你的功能:

一种)。您可以在超时时调用它(或调用do_the_rest()函数)。如果您不期望您的函数有任何结果,则更简单的方法。

乙)。或者,如果您需要等待结果,那么您应该转而使用 Promise(或者回调地狱,当然 ;-))。

没有预期结果示例:

function myFunc() {

    console.log ("Do some things");

    setTimeout(function doTheRest(){
        console.log ("Do more things...");
    }, 5000);

    // Returns undefined.
};

myFunc();

返回一个承诺的例子(注意它会改变你的函数用法):

function myFunc(someString) {

    return new Promise(function(resolve, reject) {

        var result = [someString];
        result.push("Do some things");

        setTimeout(function(){
            result.push("Do more things...");
            resolve(result.join("\n"));
        }, 5000);
    });
};


// But notice that this approach affect to the function usage...
// (It returns a promise, not actual data):
myFunc("Hello!!").then(function(data){
    console.log(data);
}).catch(function(err){
    console.error(err);
});
于 2016-10-14T06:12:28.970 回答
0

我有这个问题很长时间了,我需要的答案并不完全是这里提供的。此等待函数会导致不会占用 CPU 的同步等待。

函数waitForIt向任何地方发出 Ajax 请求并将异步标志设置为 false。函数waitF对帧执行相同的操作,函数waitD对 div 执行相同操作。Ajax 大约需要 100 ms,frame 大约是 25,div 大约是 1。

等待函数会根据你给它的时间来利用所有这些。如果它没有等待足够长的时间,然后再做一次。

在处理多个异步加载元素时我需要这个。基本上是“等到这个元素存在”。你可以在https://jsfiddle.net/h2vm29ue/上玩它。它只是利用了浏览器自然等待的东西。较长的版本https://jsfiddle.net/5cov1p0z/32/更精确。

 function waitForIt() {
     var start = new Date();
     var xhttp = new XMLHttpRequest();
     xhttp.onreadystatechange = function() {
         if (this.readyState == 4 && this.status == 200) {
            // Doesn't matter
         }
     };
     xhttp.open("GET", "WaitForIt", false);
     xhttp.send();
     var end = new Date();
 }
 //

 function waitF() {
     var start = new Date();
     var ifram = document.createElement('iframe');
     ifram.id = 'ifram';
     ifram.src = '';
     var div = document.createElement('div');
     div.id = 'timer';
     document.body.appendChild(div);
     document.getElementById('timer').appendChild(ifram);
     document.getElementById('timer').removeChild(ifram);
     document.body.removeChild(div);
     var end = new Date();
     return (end - start);
 }


 function waitD() {
     var start = new Date();
     var div = document.createElement('div');
     div.id = 'timer';
     document.body.appendChild(div);
     div.click();
     document.body.removeChild(div);
     var end = new Date();
     return (end - start);
 }

 function wait(time) {
     var start = new Date();
     var end = new Date();
     while ((end - start < time)) {

         if ((time - (end - start)) >= 200) {
             waitForIt();
         } else {
             if ((time - (end - start)) >= 50) {
                 waitF();
             } else {
                 waitD();
             }
         }
         end = new Date();
     }
     return (end - start);
 }
于 2017-04-04T15:01:20.373 回答
0

我认为这个问题很好,并指出了重要的观点和考虑。

话虽如此,我认为问题的核心在于意图和理解开发人员(您)想要控制的内容。

首先,名称sleep是一个重载的命名选择。即,“什么”将要“睡觉”;作为开发人员,我可以控制“什么”?

在任何语言引擎中,在任何操作系统进程上运行,在任何裸机或托管系统上,“开发人员”都无法控制(所有者)操作系统共享资源 CPU 内核 [和/或线程] 除非他们正在编写操作系统/进程系统本身。CPU 是一种分时资源,工作执行进度的货币是分配给系统上要执行的所有工作的“周期”。

作为应用程序/服务开发人员,最好考虑到我控制着由 os-process/language-engine 管理的工作流活动流。在某些系统上,这意味着我控制了一个 native-os-thread (可能共享 CPU 内核),而在其他系统上,这意味着我控制了一个async-continuation-workflow 链/树

在 JavaScript 的情况下,它是“后者”。

因此,当需要“睡眠”时,我打算让我的工作流程“延迟”执行一段时间,然后再继续执行其工作流程中的下一个“步骤”(阶段/活动/任务)。

这是“恰当地”的说法,作为开发人员,最容易(考虑)将工作建模为线性代码流;诉诸工作流程的组合以根据需要进行扩展。

今天,在 JavaScript 中,我们可以选择使用 1980 年代基于演员的高效多任务延续架构(重新标记为现代 Futures/Promises/then/await 等)来设计这种线性工作流。

考虑到这一点,我的回答不是提供的技术解决方案,而是关注问题本身的意图设计 视角。

我建议任何答案都从考虑上述概念开始,然后选择一个sleep能够提醒和暗示意图的名称(除了 )。

工作流程

  • 选择1:delayWorkForMs(nMsToDelay)
  • 选择2:delayAsyncSequenceForMs(msPeriod)
async delayAsyncSequenceForMs(msPeriod) {
  await new Promise(resolve => setTimeout(resolve, msPeriod));
}

请记住,任何async 函数 总是返回 a Promise,并且await只能在async 函数中使用。
(大声笑,你可能会问自己为什么......)

  • 注意事项 1:不要使用“循环”来烧毁 CPU 周期。
  • 考虑 2:在 JavaScript 模型中,当在非异步函数中时,您不能“延迟”(等待)“异步”工作流的执行(除非您在做坏事而不必要地消耗 CPU 周期)。您只能在“异步”函数中“延迟”代码步骤。
    在内部,“异步”函数被建模为每个await 关键字的入口点/延续的集合。如果您熟悉反引号插值模型,则可以“将 await”视为在概念上建模,类似于编写反引号字符串,例如:
  // Conceptualizing, using an interpolation example to illustrate
  // how to think about "await" and "async" functions
  `code${await then-restart-point}more-code${await then-restart-point}`
于 2020-11-03T19:00:36.613 回答
0

2021+ 更新

如果您正在寻找以下替代方案:

let sleep = ms => new Promise(res=>setTimeout(res,ms));

然后使用这个:

let sleep = async ms => void await Atomics.waitAsync(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms).value;

请注意,截至发布此问题时,它是第 3 阶段提案。此外,它可能要求您的站点是跨域隔离的。要查看它是否在您的浏览器中工作,(在 Stack Overflow 上)试试这个:

let sleep = async ms => void await Atomics.waitAsync(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms).value;

void async function() {
  console.log(1);
  await sleep(2000);
  console.log(2);
}()

于 2021-05-19T15:33:30.803 回答
0

JavaScript 是一个单线程执行环境。那里的每个函数都只由一个线程执行。要求“睡眠”意味着您希望将整个 VM 实例停止那么多(毫秒)秒,我认为这在 JavaScript 世界中并不是一个非常现实的要求,不仅是那个特定的功能,还有其余的如果使执行线程进入睡眠状态,所有执行都会受到影响。

首先,实际上不可能使该线程休眠。您只能通过投入一些无所事事的工作来尝试保持该线程忙碌。但是,如果您只想在某些计算中添加延迟,请将它们的执行放在单个函数上下文中,并让继续在该函数内的 setTimeout(或 Promise,如果您愿意)内发生。如果通过睡眠,您希望延迟某些事情,否则,这是不可能的。

于 2021-07-06T16:08:38.153 回答
0

如果您确实需要等待那么多秒,则当前接受的使用async/awaitand解决方案是完美的。setTimeout但是,如果您将它用于屏幕动画,那么您真的应该使用requestAnimationFrame(). 这个功能非常相似setTimeout,但是只有当动画对用户可见时才会调用回调。这意味着如果您在网站上运行动画并且用户切换选项卡,动画将暂停并节省电池寿命。

这是wait使用requestAnimationFrame. 它接收许多帧并在它们全部通过后解析:

const animationWait = (frames) => 
  new Promise((resolve) => {
    let framesPassed = 0;
    requestAnimationFrame(function loop() {
      if (++framesPassed >= frames) return resolve();
      requestAnimationFrame(loop);
    });
  });
  
// typewriter effect for demonstration
const content = document.querySelector(".content");

async function typeWriter(endText, wait) {
  content.textContent = "";
  for (const letter of endText) {
    content.textContent += letter;
    await animationWait(wait);
  }
}

typeWriter("Okay. This simple typewriter effect is an example of requestAnimationFrame.", 8);
<p>
  The animation will play below; Try switching tabs and see that   
  the animation pauses.
</p>
<code class="content"></code>

阅读更多关于requestAnimationFrame

浏览器支持 (IE10+)

于 2021-11-28T18:19:14.613 回答
-1

我使用多线程 HTML5 Worker,它将能够中止指向无响应 URL 的同步 XMLHttpRequest。这不会阻止浏览器。

https://gist.github.com/el-gringo/6990785

于 2013-10-15T12:40:39.470 回答
-1

JavaScript函数不允许任何暂停。使用同步 JavaScript,可以实现过程。过程等待 I/O 操作和休眠超时。它适用于 JavaScript 1.7。

演示:

于 2017-07-10T19:43:40.947 回答
-1

使用实际睡眠函数的问题在于 JavaScript 是单线程的,睡眠函数几乎会让您的浏览器选项卡在此期间挂起。

于 2019-03-28T09:19:48.897 回答
-1
require('deasync').sleep(100);
于 2021-10-13T14:08:25.200 回答
-2

这是一种在.hta脚本中休眠的方法,这样当脚本唤醒时,它会按顺序执行下一个命令,这在循环中是必需的。这是真正的睡眠;它不会在睡眠期间保持处理器忙碌。例如,处理器能够在睡眠期间下载和呈现页面。

一次,靠近代码的开头,去

var WSHShell = new ActiveXObject ("WScript.Shell");

对于例如 1 秒 = 1000 毫秒的睡眠,执行语句

WSHShell.Run('Sleep.js 1000', 3, true);

与脚本位于同一目录中的是文件Sleep.js,其中包含以下一行:

WScript.Sleep(WScript.Arguments (0));

(注意;0在括号中,而不是括号中。)后者是实际执行睡眠的行。前面代码片段中的参数true使调用同步。前面的3论点中的 the 似乎没有任何效果,但是您需要一些论点,所以这true是第三个论点。

微软说“WScript 对象......在调用它的属性和方法之前永远不需要被实例化,并且它总是可以从任何脚本文件中获得。”但事实并非如此。它在上述的独立文件中可用.js,但显然不在.js文件使用的.hta文件中,因此它必须在单独的文件中,如上调用。

于 2015-04-10T01:09:13.337 回答
-2

另一种可能的方式是:

var _timer;
clearTimeout(_timer);
_timer = setTimeout(function() {
    // Your code
}, 1000); // Delay for 1 s.
于 2016-03-23T14:17:12.130 回答
-2

使用三个函数:

  1. 调用setInterval启动循环的函数
  2. 一个函数,它调用clearInterval停止循环,然后调用setTimeout睡眠,最后setTimeout在回调中调用以重新启动循环
  3. 一个循环,它跟踪迭代次数,设置睡眠次数和最大次数,一旦达到睡眠次数就调用睡眠函数,并在达到clearInterval最大次数后调用

var foo = {};

function main()
{
  'use strict';

  /* Initialize global state */
  foo.bar = foo.bar || 0;

  /* Initialize timer */
  foo.bop = setInterval(foo.baz, 1000);
}

sleep =
  function(timer)
  {
    'use strict';
    clearInterval(timer);
    timer = setTimeout(function(){main()}, 5000);
  };

foo.baz =
  function()
  {
    'use strict';

    /* Update state */
    foo.bar = Number(foo.bar + 1) || 0;

    /* Log state */
    console.log(foo.bar);

    /* Check state and stop at 10 */
    (foo.bar === 5) && sleep(foo.bop);
    (foo.bar === 10) && clearInterval(foo.bop);
  };

main();

事件循环

参考

于 2016-07-02T00:25:29.277 回答
-2

现在也可以使用本机模块 util 来承诺常规同步功能。

const { promisify } = require('util')
const sleep = promisify(setTimeout)

module.exports = () => {
  await someAsyncFunction()
  await sleep(2000)
  console.log('2 seconds later...')
}
于 2017-12-19T16:34:30.657 回答
-2

我有一个类似的问题,必须等待控制存在并检查间隔。由于在 JavaScript 中没有真正的睡眠、等待或暂停,并且 Internet Explorer 不正确支持使用 await / async,我使用 setTimeOut 并注入函数以防成功找到元素。下面是完整的示例代码,大家可以在自己的项目中复现和使用:

<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript">
        var ElementSearchStatus = {
            None: 0,
            Found: 1,
            NotFound: 2,
            Timeout: 3
        };

        var maxTimeout = 5;
        var timeoutMiliseconds = 1000;

        function waitForElement(elementId, count, timeout, onSuccessFunction) {
            ++count;
            var elementSearchStatus = existsElement(elementId, count, timeout);
            if (elementSearchStatus == ElementSearchStatus.None) {
                window.setTimeout(waitForElement, timeoutMiliseconds, elementId, count, timeout, onSuccessFunction);
            }
            else {
                if (elementSearchStatus == ElementSearchStatus.Found) {
                    onSuccessFunction();
                }
            }
        }

        function existsElement(elementId, count, timeout) {
            var foundElements = $("#" + elementId);
            if (foundElements.length > 0 || count > timeout) {
                if (foundElements.length > 0) {
                    console.log(elementId + " found");
                    return ElementSearchStatus.Found;
                }
                else {
                    console.log("Search for " + elementId + " timed out after " + count + " tries.");
                    return ElementSearchStatus.Timeout;
                }
            }
            else {
                console.log("waiting for " + elementId + " after " + count + " of " + timeout);
                return ElementSearchStatus.None;
            }
        }

        function main() {
            waitForElement("StartButton", 0, maxTimeout, function () {
                console.log("found StartButton!");
                DoOtherStuff("StartButton2")
            });
        }

        function DoOtherStuff(elementId) {
            waitForElement(elementId, 0, maxTimeout, function () {
                console.log("found " + elementId);
                DoOtherStuff("StartButton3");
            });
        }
    </script>
</head>
<body>
    <button type="button" id="StartButton" onclick="main();">Start Test</button>
    <button type="button" id="StartButton2" onclick="alert('Hey ya Start Button 2');">Show alert</button>
</body>
</html>
于 2018-09-19T08:28:24.017 回答
-2

一种非常简单的睡眠方法,它将与任何运行 JavaScript 的东西兼容……这段代码已经过 500 个条目的测试,CPU 和内存使用情况在我的网络浏览器上仍然不可见。

这是一个等待节点变为可见的函数......

此函数创建一个新上下文function () {}以避免递归。我们在这个新上下文中放置了与调用者代码相同的代码。我们使用该函数Timeout在几秒钟后调用我们的函数。

var get_hyper = function(node, maxcount, only_relation) {
    if (node.offsetParent === null) {
        // node is hidden
        setTimeout(function () { get_hyper(node, maxcount, only_relation)}, 
                   1000);
        return;
    };

    // Enter the code here that waits for that node becoming visible
    // before getting executed.

};
于 2018-10-05T14:11:57.470 回答
-2

我得到了 Promise is not a constructor 使用最佳答案。如果你导入 bluebird,你可以这样做。在我看来,这是最简单的解决方案。

import * as Promise from 'bluebird';

await Promise.delay(5000)
于 2019-02-26T04:48:57.340 回答
-3

LiveScript(编译为 JavaScript)中,您可以执行以下操作:

sleep = (ms, func) -> set-timeout func, ms

console.log "hello-1"
<- sleep 2000ms
console.log "hello-2"
<- sleep 2000ms
console.log "hello-3"
于 2016-04-06T20:28:01.290 回答
-6

这可能会奏效。它在 C 和 JavaScript 中对我有用。

function sleep(time) {
  var x = 0;
  for(x = 0;x < time;x++) {/* Do nothing */}
}
于 2016-05-31T01:01:13.453 回答
-7

到目前为止,我读过的每一个解决方案都像是“让我们去睡觉,看看明天发生了什么”。

setInterval(callback, ti​​me)会等待很长时间,然后调用回调,同时阻塞运行时。“setInterval”的当前实现远非线程保存,甚至不考虑并发性。

虽然提到的稀疏解决方案看起来像 C#(),但它们仍然不像在 C#/.NET 中那样工作。它们仍然像在 C 中一样工作。

JavaScript 目前不提供实现真正多线程的架构。最好的方法是 TypeScript,但这仍然缺乏真正的解决方案,以至于它......很痛苦。JavaScript、jQuery、AJAX、jNode,甚至 TypeScript 都只是一群依赖于实现者情绪好坏的崇拜者。事实。句号。

于 2017-06-27T12:18:24.473 回答
-9

或者只是创建这个:

function yourFunction(){

   // Do something
   setInterval(myFunc(), 1000);
   // Do something else
}

function myFunc(){
   return;
}

这只会等待指定的时间间隔并调用什么都不做的函数。

于 2013-02-15T19:48:37.223 回答