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

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

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


当前回答

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

“JavaScript是单线程的”不是有效答案。例如,在工作线程中运行睡眠函数不会阻止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中使用。

其他回答

我也遇到过类似的问题,必须等待控件的存在并每隔一段时间进行检查。由于JavaScript中没有真正的休眠、等待或暂停,并且Internet Explorer中不正确支持使用wait/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>

sleep()的JavaScript版本是什么?

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

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

两个异步函数同时运行

最好将它放在函数sleep()中,然后等待睡眠()。要使用它,需要一些上下文:

函数sleep(ms){return new Promise(r=>setTimeout(r,ms));}(异步函数slowDemo(){console.log(“启动慢演示…”);等待睡眠(2000);console.log('lowDemo:两秒后…');})();(异步函数fastDemo(){console.log('开始快速演示…');等待睡眠(500);for(设i=1;i<6;i++){console.log('上次演示:'+(i*0.5)+'秒后…');等待睡眠(500);}})();.作为控制台包装{最大高度:100%!重要;顶部:0;}

两个异步调用依次运行–一个接一个

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

函数sleep(ms){return new Promise(r=>setTimeout(r,ms));}(异步()=>{await(异步函数slowDemo(){console.log(“启动慢演示…”);等待睡眠(2000);console.log('slowDemo:两秒后…完成!');})();(异步函数fastDemo(){console.log('开始快速演示…');等待睡眠(500);设i=-2;对于(i=1;i<5;i++){console.log('上次演示:'+(i*0.5)+'秒后…');等待睡眠(500);}console.log('fastDemo:'+(i*0.5)+'秒后。已完成!');})();})();.作为控制台包装{最大高度:100%!重要;顶部:0;}

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

或使用字体:

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

将其用作:

await sleep(<duration>);

演示:

功能睡眠(ms){return new Promise(resol=>setTimeout(resolve,ms));}异步函数demo(){for(设i=0;i<5;i++){console.log(`等待${i}秒…`);等待睡眠(i*1000);}console.log('Done');}demo();

注意,

await只能在前缀为async关键字的函数中执行,或者在越来越多的环境中在脚本的顶层执行。await只暂停当前的异步函数。这意味着它不会阻止脚本的其余部分的执行,这在大多数情况下都是您想要的。如果您确实需要一个阻塞构造,请使用Atomics.wait查看这个答案,但请注意,大多数浏览器都不允许在浏览器的主线程上使用它。

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

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

兼容性

承诺在Node v0.12+中得到支持,在浏览器中得到广泛支持,IE除外async/await登陆V8,自Chrome 55(2016年12月发布)以来默认启用它于2016年10月登陆Node 7并于2016年11月登陆Firefox Nightly

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

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

演示:

演示睡眠演示可暂停程序

从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);
    }
  }