我正在为个人需求开发一个控制台脚本。我需要能够暂停很长时间,但是,根据我的研究,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 不承认这一点。
我怎样才能实现这种延长的暂停?
require("child_process").execSync('php -r "sleep($argv[1]);" ' + seconds);
2021 年 1 月更新:您甚至可以使用 --experimental-repl-await
标志在 Node REPL 交互中进行
$ node --experimental-repl-await
> const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
> await delay(1000) /// waiting 1 second.
老问题的新答案。今天(2017 年 1 月2019 年 6 月)要容易得多。您可以使用 new async/await
syntax。例如:
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);
});
}
The proposal is in stage 3。您现在可以通过使用 webpack 5 (alpha) 来使用它,
更多信息:
Nodejs 中的 Harmony 标志:https://nodejs.org/en/docs/es6/
所有 NodeJS 版本供下载:https://nodejs.org/en/download/releases/
没有任何依赖关系的最短解决方案:
await new Promise(resolve => setTimeout(resolve, 5000));
let sleep = require('util').promisify(setTimeout);
长三个字符,但可重复使用且更易读
resolve
而不是 done
。即await new Promise(resolve => setTimeout(resolve, 5000))
最好的方法是将代码分解为多个函数,如下所示:
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 的解决方案,但更简洁且更易于扩展。
debugger;
这是一个简单的阻塞技术:
var waitTill = new Date(new Date().getTime() + seconds * 1000);
while(waitTill > new Date()){}
只要您的脚本中不会发生任何其他事情(如回调),它就会被阻止。但由于这是一个控制台脚本,也许它就是你所需要的!
wait
,它会阻塞并且它可以用于某些测试目的。正是我正在寻找的。
spin-wait
。
SLEEP.EXE
。
将延迟后要执行的代码放入 setTimeout
回调中:
console.log('Welcome to My Console,');
setTimeout(function() {
console.log('Blah blah blah blah extra-blah');
}, 3000);
node-fibers
的解决方案。 Check it out.
在节点 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
奇迹般有效。
使用现代 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
,所以这真的不是问题。今天所有的现代浏览器support它。
对于那些不习惯 async/await
和粗箭头运算符的人,稍微了解一下 sleep
函数,这是编写它的冗长方式:
function sleep(millis) {
return new Promise(function (resolve, reject) {
setTimeout(function () { resolve(); }, millis);
});
}
但是,使用胖箭头运算符可以使其更小(并且更优雅)。
async
的 sleep 函数,而其他一切都保持不变。不过,使用 async
可能更清楚。
async
。用你的建议编辑了我的答案。我认为它不会使代码更清晰;为此,我会求助于 JSDoc。
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
您可以使用此www.npmjs.com/package/sleep
var sleep = require('sleep');
sleep.sleep(10); // sleep for ten seconds
如果您想“编码高尔夫”,您可以在此处制作其他一些答案的较短版本:
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);
await
。它有点创建回调,暂停事情,然后在回调返回时重新启动代码。回调返回一个值,但在这种情况下我们不关心它,所以 await
的左侧没有任何内容。
await require('util').promisify(setTimeout)(1000);
这个问题很老了,但最近 V8 添加了可以完成 OP 要求的生成器。在 suspend 或 gen-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');
})();
相关阅读(通过无耻的自我宣传):What's the Big Deal with Generators?。
yield setTimeout(suspend.resume(), 10000);
--harmony
标志后面,根据 node.green,它们至少在 v4 之后没有任何标志可用.8.4:node.green/#ES2015-functions-generators-basic-functionality。但是请注意,较新的 async/await
语法现在提供了更好的解决方案,不需要像 suspend
这样的额外库。有关示例,请参见此答案:stackoverflow.com/a/41957152/376789。自 v7.10 起,异步函数可用(无标志)。
在 Linux/nodejs 上,这对我有用:
const spawnSync = require('child_process').spawnSync; var sleep = spawnSync('sleep', [1.5]);
它正在阻塞,但它不是一个繁忙的等待循环。
您指定的时间以秒为单位,但可以是一小部分。我不知道其他操作系统是否有类似的命令。
sleep
自 UNIX 早期 en.wikipedia.org/wiki/Sleep_%28Unix%29 以来几乎无处不在且实用。只有 Windows 可能不存在的“不稀有”操作系统(但是您可以尝试 child_process.spawnSync('timeout', ['/T', '10'])
我最近创建了一个更简单的抽象,称为 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.
此外,任何异步函数都可以在同步模式下调用。检查示例。
TypeError: Object #<Object> has no method 'miliseconds'
wait.for/paralell-tests.js
得到它后,我遇到了另一个与未定义属性等相关的错误。所以我也需要复制它们。为什么不以不需要的方式组织代码?
尝试使用 Promise,它在 NodeJS 中对我有用
一个班轮
await new Promise(resolve => setTimeout(resolve, 5000));
或将其作为 NodeJS
中的函数以重复使用
const sleep = async (milliseconds) => {
await new Promise(resolve => setTimeout(resolve, milliseconds));
}
使用类似的功能
await sleep(5000)
由于 javascript 引擎 (v8) 基于事件队列中的事件序列运行代码,因此没有严格的 javascript 在指定时间后准确触发执行。也就是说,当您设置几秒钟以稍后执行代码时,触发代码纯粹基于事件队列中的顺序。因此触发代码执行可能需要超过指定时间。
所以 Node.js 紧随其后,
process.nextTick()
稍后运行代码而不是 setTimeout()。例如,
process.nextTick(function(){
console.log("This will be printed later");
});
从 Node.js 15 起,您可以使用 Timers Promises API。您不必再承诺 setTimeout
或依赖第 3 方库。
import { setTimeout } from 'timers/promises';
await setTimeout(1000);
由于 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
函数成为 new Promise(...)
中的 resolve
回调。
另请注意,这是异步睡眠。它不会阻塞事件循环。如果您需要阻塞睡眠,请使用此库,该库借助 C++ 绑定实现阻塞睡眠。 (尽管在 Node 等异步环境中需要阻塞睡眠的情况很少见。)
https://github.com/erikdubbelboer/node-sleep
为了在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'))
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
关键字后跟 *
在现代 Javascript 中称为生成器函数。 npm 包 co
提供了一个运行器函数来运行生成器。
本质上,生成器函数提供了一种使用 yield
关键字暂停函数执行的方法,同时,生成器函数中的 yield
使得在生成器内部和调用者之间交换信息成为可能。这为调用者提供了一种机制,可以从异步调用的 promise
中提取数据,并将解析后的数据传递回生成器。实际上,它使异步调用同步。
这是一个基于 dirty blocking approach suggested by @atlex2 的 moment.js 风格的模块。 仅用于测试。
const moment = require('moment');
let sleep = (secondsToSleep = 1) => {
let sleepUntill = moment().add(secondsToSleep, 'seconds');
while(moment().isBefore(sleepUntill)) { /* block the process */ }
}
module.exports = sleep;
很简单,我们将等待 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;
}
})();
对于某些人来说,接受的答案不起作用,我找到了另一个答案,它对我有用:How can I pass a parameter to a setTimeout() callback?
var hello = "Hello World";
setTimeout(alert, 1000, hello);
'hello' 是被传递的参数,你可以在超时时间之后传递所有的参数。感谢@Fabio Phms 的回答。
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
}
)
如果您只是出于测试目的而需要暂停当前线程执行,请尝试以下操作:
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
其他答案很好,但我想我会采取不同的策略。
如果您真正想要的是减慢 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 表示不缓冲输出。
在阅读了这个问题的答案后,我整理了一个简单的函数,如果你需要,它也可以进行回调:
function waitFor(ms, cb) {
var waitTill = new Date(new Date().getTime() + ms);
while(waitTill > new Date()){};
if (cb) {
cb()
} else {
return true
}
}
不定期副业成功案例分享
sleep(1000)
前面的await
关键字let sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
对于像我这样的 oneliner 怪胎 :)let sleep = require('util').promisify(setTimeout);
适用于 Node 7.6+ 并提高了可读性promisify
食谱)。