有没有比下面的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中使用。

其他回答

在服务器端,您可以使用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);
});

如果您想休眠一个匿名函数,就像您创建的处理程序一样,我建议您使用以下方法:

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

这段代码表示“如果等待条件尚未满足,请使用这些参数再次调用此函数。”。

(见2016年更新答案)

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

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

因此,你基本上坚持了别人的建议——你需要将代码分解为多个函数。

那么,你的问题有点错误。没有办法按照你想要的方式睡觉,你也不应该追求你建议的解决方案。

总结一下(就像前面的回答中所说的):

JavaScript中没有内置的睡眠函数。您应该使用setTimeout或setInterval来实现类似的效果。

如果你真的想,你可以用一个for循环来模拟睡眠功能,比如原始问题中所示的循环,但这会让你的CPU工作得很疯狂。在Web Worker内部,另一种解决方案是向非响应IP地址发出同步XMLHttpRequest,并设置适当的超时。这将避免CPU利用率问题。下面是一个代码示例:

//仅在web工作程序内部工作函数休眠(毫秒){var req=新XMLHttpRequest();请求打开(“GET”,“http://192.0.2.0/“,错误);req.timeout=毫秒;尝试{请求发送();}捕获(ex){}}console.log('休眠1秒…');睡眠(1000);console.log(“睡眠!”);console.log('休眠5秒…')睡眠(5000);console.log(“睡眠!”);

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