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

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

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


当前回答

在服务器端,您可以使用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()函数是实现它的唯一方法,而且,除此之外:

这不仅会暂停函数,还会暂停整个事件循环。因此,将不会参加其他活动。它使您的CPU处于100%负载。

因此,如果您需要它作为浏览器脚本,并且不希望出现这些可怕的效果,我必须说,您应该以某种方式重新思考您的功能:

a) 。您可以在超时时调用它(或调用do_the_rest()函数)。如果您不期望从函数中得到任何结果,则使用更简单的方法。

b) 。或者,如果你需要等待结果,那么你应该使用promise(当然,也可以使用回调地狱;-))。

无预期结果示例:

function myFunc() {

    console.log ("Do some things");

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

    // Returns undefined.
};

myFunc();

返回promise的示例(注意它会改变函数的用法):

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

其他回答

如果您真的想完全阻塞主线程并防止事件循环从事件队列中拉出,那么这里有一个很好的方法可以做到这一点,而不需要创建任何函数、新的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

在Date.now()上使用performance.now(()的好处是Date对象是

受到时钟偏斜和系统时钟调整的影响。这个时间的价值可能不总是单调增加随后的值可以减小或保持不变。*

通常,performance.now()更适合高精度地测量时间差异。

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

如果您使用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');

这里有一种在.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似乎没有任何效果,但你需要一些参数,以便true是第三个参数。

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

在Firebug(可能还有其他JavaScript控制台)中,只有在指定的睡眠时间(…)之后,点击enter后才会发生任何事情

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

使用示例:

函数sleepFor(sleepDuration){var now=new Date().getTime();而(newDate().getTime()<now+sleepDuration){/*什么都不做*/}}函数sleepThenAt(){sleepFor(2000);console.log(“您好,JavaScript睡眠!”);}sleepThenAt()

注:仅用于调试和开发

如果你想要比setTimeout和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毫秒,…”)