589

我正在为个人需求开发一个控制台脚本。我需要能够暂停很长时间,但是,根据我的研究,Node.js 无法按要求停止。一段时间后,阅读用户的信息变得越来越困难......我已经看到了一些代码,但我相信他们必须在其中包含其他代码才能工作,例如:

    setTimeout(function() {
    }, 3000);

但是,我需要这行代码之后的所有内容才能在一段时间后执行。

例如,

    // start of code
    console.log('Welcome to my console,');

    some-wait-code-here-for-ten-seconds...

    console.log('Blah blah blah blah extra-blah');
    // end of code

我也见过类似的东西

    yield sleep(2000);

但是 Node.js 不承认这一点。

我怎样才能实现这种延长的暂停?

4

25 回答 25

756

2021 年 1 月更新:您甚至可以在 Node REPL 交互式使用--experimental-repl-await标志中进行操作

$ node --experimental-repl-await
> const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
> await delay(1000) /// waiting 1 second.

老问题的新答案。今天(2017年 1月,2019 年 6 月)要容易得多。您可以使用async/await语法。例如:

async function init() {
  console.log(1);
  await sleep(1000);
  console.log(2);
}

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

要在不安装和插件的情况下使用async/await开箱即用,您必须使用 node-v7 或 node-v8,使用--harmony标志。

2019 年 6 月更新:通过使用最新版本的 NodeJS,您可以立即使用它。无需提供命令行参数。今天甚至谷歌浏览器也支持它。

2020 年 5 月更新: 很快您将能够在await异步函数之外使用语法。在这个例子中的顶层

await sleep(1000)
function sleep(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

该提案处于第 3 阶段。您现在可以通过使用 webpack 5 (alpha) 来使用它,

更多信息:

于 2017-01-31T12:05:14.897 回答
519

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

await new Promise(resolve => setTimeout(resolve, 5000));
于 2018-03-06T20:47:32.153 回答
249

最好的方法是将代码分解为多个函数,如下所示:

function function1() {
    // stuff you want to happen right away
    console.log('Welcome to My Console,');
}

function function2() {
    // all the stuff you want to happen after that pause
    console.log('Blah blah blah blah extra-blah');
}

// call the first chunk of code right away
function1();

// call the rest of the code and have it execute after 3 seconds
setTimeout(function2, 3000);

它类似于JohnnyHK的解决方案,但更整洁且更易于扩展。

于 2013-01-10T01:46:21.703 回答
183

这是一个简单的阻塞技术:

var waitTill = new Date(new Date().getTime() + seconds * 1000);
while(waitTill > new Date()){}

只要您的脚本中不会发生任何其他事情(如回调),它就会被阻止。但由于这是一个控制台脚本,也许它就是你所需要的!

于 2016-06-01T17:51:08.363 回答
159

将延迟后要执行的代码放入setTimeout回调中:

console.log('Welcome to My Console,');
setTimeout(function() {
    console.log('Blah blah blah blah extra-blah');
}, 3000);
于 2013-01-10T01:44:53.520 回答
98

在节点 7.6.0 或更高版本上

Node原生支持等待:

const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));

那么如果你可以使用异步函数:

await sleep(10000); // sleep for 10 seconds

或者:

sleep(10000).then(() => {
  // This will execute 10 seconds from now
});

在较旧的节点版本上(原始答案)

我想要一个在 Windows 和 Linux 中工作的异步睡眠,而不需要长时间循环占用我的 CPU。我尝试了 sleep 包,但它不会安装在我的 Windows 机器上。我最终使用:

https://www.npmjs.com/package/system-sleep

要安装它,请键入:

npm install system-sleep

在您的代码中,

var sleep = require('system-sleep');
sleep(10*1000); // sleep for 10 seconds

奇迹般有效。

于 2017-01-13T18:56:36.873 回答
69

使用现代 Javascript 的简单优雅的睡眠功能

function sleep(millis) {
    return new Promise(resolve => setTimeout(resolve, millis));
}

没有依赖,没有回调地狱;就是这样 :-)


考虑到问题中给出的示例,这就是我们在两个控制台日志之间休眠的方式:

async function main() {
    console.log("Foo");
    await sleep(2000);
    console.log("Bar");
}

main();

“缺点”是您的主要功能现在也必须async如此。但是,考虑到您已经在编写现代 Javascript 代码,您可能(或至少应该!)在您的代码中使用async/ await,所以这真的不是问题。今天所有的现代浏览器都支持它。

sleep为那些不习惯和胖箭头运算符的人提供一些功能async/await,这是编写它的冗长方式:

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

但是,使用胖箭头运算符可以使其更小(并且更优雅)。

于 2017-10-13T00:14:29.037 回答
52

你可以使用这个www.npmjs.com/package/sleep

var sleep = require('sleep');
sleep.sleep(10); // sleep for ten seconds
于 2016-04-22T17:40:54.683 回答
37

如果您想“编码高尔夫”,您可以在此处制作其他一些答案的较短版本:

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

但在我看来,真正理想的答案是使用 Node 的util库及其promisify函数,它就是为这类事情而设计的(制作以前存在的非基于 Promise 的东西的基于 Promise 的版本):

const util = require('util');
const sleep = util.promisify(setTimeout);

在任何一种情况下,您都可以通过使用await来调用您的sleep函数来暂停:

await sleep(1000); // sleep for 1s/1000ms

编辑:如评论中所述,您甚至可以将其减少到一行:

const sleep = require('util').promisify(setTimeout);

或者,如果您甚至不想费心制作sleep函数:

await require('util').promisify(setTimeout)(1000);
于 2017-10-24T00:38:40.510 回答
36

这个问题很老了,但最近 V8 添加了可以完成 OP 要求的生成器。在诸如suspendgen-run之类的库的帮助下,生成器通常最容易用于异步交互。

下面是一个使用挂起的例子:

suspend(function* () {
    console.log('Welcome to My Console,');
    yield setTimeout(suspend.resume(), 10000); // 10 seconds pass..
    console.log('Blah blah blah blah extra-blah');
})();

相关阅读(通过无耻的自我宣传):发电机有什么大不了的?.

于 2013-08-21T14:11:27.147 回答
22

在 Linux/nodejs 上,这对我有用:

const spawnSync = require('child_process').spawnSync;

var sleep = spawnSync('sleep', [1.5]);

它正在阻塞,但它不是一个繁忙的等待循环。

您指定的时间以秒为单位,但可以是一小部分。我不知道其他操作系统是否有类似的命令。

于 2016-11-18T18:50:04.200 回答
14

我最近创建了一个更简单的抽象,称为wait.for以在同步模式下调用异步函数(基于节点光纤)。还有一个基于即将推出的 ES6 生成器的版本。

https://github.com/luciotato/waitfor

使用wait.for,您可以调用任何标准的 nodejs 异步函数,就好像它是一个同步函数一样,而不会阻塞节点的事件循环。

您可以在需要时按顺序编码,这(我猜)非常适合简化您的脚本以供个人使用。

使用wait.for您的代码将是:

require('waitfor')

..in a fiber..
//start-of-code
console.log('Welcome to My Console,');
wait.miliseconds(10*1000); //defined in waitfor/paralell-tests.js - DOES NOT BLOCK
console.log('Blah blah blah blah extra-blah');
//endcode. 

此外,任何异步函数都可以在同步模式下调用。检查示例。

于 2013-09-06T13:58:46.873 回答
8

由于javascript引擎(v8)基于事件队列中的事件序列运行代码,因此没有严格的javascript在指定时间后准确触发执行。也就是说,当您设置几秒钟以稍后执行代码时,触发代码纯粹基于事件队列中的顺序。因此触发代码执行可能需要超过指定时间。

所以 Node.js 紧随其后,

process.nextTick()

稍后运行代码而不是 setTimeout()。例如,

process.nextTick(function(){
    console.log("This will be printed later");
});
于 2013-01-10T11:22:37.633 回答
8

尝试使用 Promise,它在 NodeJS 中对我有用

一个班轮

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

或将其作为NodeJS重复使用的功能

const sleep = async (milliseconds) => {
    await new Promise(resolve => setTimeout(resolve, milliseconds));
}

使用类似的功能

await sleep(5000)
于 2021-06-10T08:15:54.223 回答
2

有了 ES6 支持Promise,我们可以在没有任何第三方帮助的情况下使用它们。

const sleep = (seconds) => {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, (seconds * 1000));
    });
};

// We are not using `reject` anywhere, but it is good to
// stick to standard signature.

然后像这样使用它:

const waitThenDo(howLong, doWhat) => {
    return sleep(howLong).then(doWhat);
};

请注意,该doWhat函数resolve成为new Promise(...).

另请注意,这是异步睡眠。它不会阻塞事件循环。如果您需要阻塞睡眠,请使用此库,该库借助 C++ 绑定实现阻塞睡眠。(尽管在 Node 等异步环境中需要阻塞睡眠的情况很少见。)

https://github.com/erikdubbelboer/node-sleep

于 2017-05-18T00:34:15.630 回答
1

为了在javascript中“等待”,使用promise是最佳答案所示的方法。

那么如何使用呢?

下面是一个简单的例子,一个 5 秒的子进程以非阻塞的方式为一个 4 秒的主进程排队参数。

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

const process = async (items, prepTask, mainTask) => {
    const queue = [];
    let done = false;

    items.forEach((item, i) => {
        prepTask(item).then(() => {
            queue.push(item);
            if (i == items.length -1) {
                done = true;
            }
        })
    })

    while (!done || queue.length) {
        if (queue.length) {
            const workload = queue.shift();
            await mainTask(workload)
        } else {
            console.log('waiting for subtask to queue')
            await wait(1);
        }
    }
}

// Usage Example

const ids = [1,2,3,4,5,6,7,8,9,10];

const prepTask = async (id) => {
    await wait(id * 5)
    return id * 5;
}

const mainTask = async (workload) => {
    console.log('excuting workload: ', workload);
    const result = await wait(4);
    return { workload, result }
}

process(ids, prepTask, mainTask)
    .then(() => console.log('done'))
于 2021-10-31T21:40:43.733 回答
0
let co = require('co');
const sleep = ms => new Promise(res => setTimeout(res, ms));

co(function*() {
    console.log('Welcome to My Console,');
    yield sleep(3000);
    console.log('Blah blah blah blah extra-blah');
});

上面这段代码是解决 Javascript 的异步回调地狱问题的副作用。这也是我认为 Javascript 成为后端有用语言的原因。实际上,在我看来,这是引入现代 Javascript 的最令人兴奋的改进。要完全理解它是如何工作的,需要完全理解生成器是如何工作的。function后跟 a的关键字*在现代 Javascript 中称为生成器函数。npm 包co提供了一个运行生成器的运行器函数。

本质上,生成器函数提供了一种使用yield关键字暂停函数执行的方法,同时,yield在生成器函数中,可以在生成器内部和调用者之间交换信息。这为调用者提供了一种机制,可以从异步调用中提取数据promise并将解析的数据传递回生成器。实际上,它使异步调用同步。

于 2017-03-08T09:58:52.340 回答
0

这是一个moment.js 风格的模块,基于@atlex2 建议的脏阻塞方法仅用于测试

const moment = require('moment');

let sleep = (secondsToSleep = 1) => {
    let sleepUntill = moment().add(secondsToSleep, 'seconds');
    while(moment().isBefore(sleepUntill)) { /* block the process */ }
}

module.exports = sleep;
于 2017-11-08T14:11:34.580 回答
-1

很简单,我们将等待 5 秒以等待某个事件发生(这将由代码中其他地方的 done 变量设置为 true 来指示)或者当超时到期时,我们将每 100 毫秒检查一次

    var timeout=5000; //will wait for 5 seconds or untildone
    var scope = this; //bind this to scope variable
    (function() {
        if (timeout<=0 || scope.done) //timeout expired or done
        {
            scope.callback();//some function to call after we are done
        }
        else
        {
            setTimeout(arguments.callee,100) //call itself again until done
            timeout -= 100;
        }
    })();
于 2017-03-22T14:54:04.667 回答
-1

对于某些人来说,接受的答案不起作用,我找到了另一个答案,它对我有用:如何将参数传递给 setTimeout() 回调?

var hello = "Hello World";
setTimeout(alert, 1000, hello); 

'hello' 是被传递的参数,你可以在超时时间之后传递所有的参数。感谢@Fabio Phms 的回答。

于 2017-04-13T18:49:13.730 回答
-1
function doThen(conditional,then,timer) {
    var timer = timer || 1;
    var interval = setInterval(function(){
        if(conditional()) {
            clearInterval(interval);
            then();
        }
    }, timer);
}

示例用法:

var counter = 1;
doThen(
    function() {
        counter++;
        return counter == 1000;
    },
    function() {
        console.log("Counter hit 1000"); // 1000 repeats later
    }
)
于 2020-06-24T16:26:53.627 回答
-2

如果您只是出于测试目的而需要暂停当前线程执行,请尝试以下操作:

function longExecFunc(callback, count) {

    for (var j = 0; j < count; j++) {
        for (var i = 1; i < (1 << 30); i++) {
            var q = Math.sqrt(1 << 30);
        }
    }
    callback();
}
longExecFunc(() => { console.log('done!')}, 5); //5, 6 ... whatever. Higher -- longer
于 2016-11-29T09:19:15.423 回答
-3

其他答案很好,但我想我会采取不同的策略。

如果您真正想要的是减慢 linux 中的特定文件:

 rm slowfile; mkfifo slowfile; perl -e 'select STDOUT; $| = 1; while(<>) {print $_; sleep(1) if (($ii++ % 5) == 0); }' myfile > slowfile  &

节点 myprog 慢文件

这将每五行休眠 1 秒。节点程序将与编写器一样慢。如果它正在做其他事情,它们将继续以正常速度。

mkfifo 创建一个先进先出的管道。这就是使这项工作发挥作用的原因。perl 行将根据您的需要快速写入。$|=1 表示不缓冲输出。

于 2017-03-13T21:11:57.753 回答
-4

在阅读了这个问题的答案后,我整理了一个简单的函数,如果你需要,它也可以进行回调:

function waitFor(ms, cb) {
  var waitTill = new Date(new Date().getTime() + ms);
  while(waitTill > new Date()){};
  if (cb) {
    cb()
  } else {
   return true
  }
}
于 2016-11-06T08:08:38.153 回答
-5

有关更多信息

yield sleep(2000); 

你应该检查Redux-Saga。但它特定于您选择 Redux 作为您的模型框架(尽管严格来说不是必需的)。

于 2016-09-09T09:24:46.753 回答