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

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

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


当前回答

这是一种阻塞型睡眠。发现在需要顺序执行的测试活动中更容易遵循。它可以被称为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;
  }

其他回答

我相信有一百万种方法可以做得更好,但我想我可以通过创建一个对象来尝试一下:

// 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 // // //

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

我同意其他海报。忙着睡觉是个坏主意。

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

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

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

这里有一种在.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中使用,所以它必须在一个单独的文件中,如上所述调用。