我正在为个人需求开发一个控制台脚本。我需要能够暂停更长的时间,但是,根据我的研究,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不能识别这个。
我怎样才能实现这种延长的暂停?
我最近创建了一个更简单的抽象概念,叫做等待。用于在同步模式下调用异步函数(基于节点光纤)。还有一个基于即将到来的ES6生成器的版本。
https://github.com/luciotato/waitfor
使用等。对于,你可以调用任何标准的nodejs async函数,就像它是一个同步函数一样,而不会阻塞node的事件循环。
您可以在需要时按顺序编码,这(我猜)完美地简化了您的脚本供个人使用。
使用等。你的代码将是:
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.
同样,任何async函数都可以在Sync模式下调用。
检查例子。
Node 7.6.0或更高版本
节点支持本地等待:
const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
然后如果你可以使用异步函数:
await sleep(10000); // sleep for 10 seconds
or:
sleep(10000).then(() => {
// This will execute 10 seconds from now
});
在较旧的Node版本上(原始答案)
我想要一个在Windows和Linux中工作的异步睡眠,而不会占用CPU很长的while循环。我尝试了睡眠包,但它无法安装在我的Windows盒子上。我最终使用:
https://www.npmjs.com/package/system-sleep
要安装它,输入:
npm install system-sleep
在你的代码中,
var sleep = require('system-sleep');
sleep(10*1000); // sleep for 10 seconds
效果非常好。
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,您可以开箱即用。不需要提供命令行参数。即使谷歌Chrome今天也支持它。
2020年5月更新:
很快你就可以在async函数之外使用await语法了。在顶层,比如这个例子
await sleep(1000)
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
提案已进入第三阶段。
今天你可以通过webpack 5 (alpha)使用它,
更多信息:
Nodejs中的和谐标志:https://nodejs.org/en/docs/es6/
所有NodeJS版本下载:https://nodejs.org/en/download/releases/
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');
});
This code above is the side effect of the solving Javascript's asynchronous callback hell problem. This is also the reason I think that makes Javascript a useful language in the backend. Actually this is the most exciting improvement introduced to modern Javascript in my opinion. To fully understand how it works, how generator works needs to be fully understood. The function keyword followed by a * is called a generator function in modern Javascript. The npm package co provided a runner function to run a generator.
本质上,生成器函数提供了一种使用yield关键字暂停函数执行的方法,同时,生成器函数中的yield使生成器内部和调用者之间交换信息成为可能。这为调用方提供了一种机制,可以从异步调用的promise中提取数据,并将已解析的数据传递回生成器。实际上,它使异步调用同步化。
有了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函数变成了新的Promise(…)中的解析回调函数。
还要注意,这是异步睡眠。它不会阻塞事件循环。如果你需要阻塞睡眠,使用这个库,它在c++绑定的帮助下实现了阻塞睡眠。(尽管在Node中像异步环境一样需要阻塞睡眠的情况很少。)
https://github.com/erikdubbelboer/node-sleep
使用现代Javascript的简单而优雅的睡眠函数
function sleep(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
没有依赖,没有回调;就是这样:-)
考虑到问题中给出的例子,这是我们在两个控制台日志之间睡眠的方式:
async function main() {
console.log("Foo");
await sleep(2000);
console.log("Bar");
}
main();
“缺点”是你的主函数现在也必须是异步的。但是,考虑到您已经在编写现代Javascript代码,您可能(或者至少应该!)在所有代码中使用async/await,所以这真的不是一个问题。现在所有的浏览器都支持它。
对于那些不习惯async/await和胖箭头操作符的人,稍微深入了解一下sleep函数,下面是详细的书写方式:
function sleep(millis) {
return new Promise(function (resolve, reject) {
setTimeout(function () { resolve(); }, millis);
});
}
但是,使用胖箭头操作符会使它更小(也更优雅)。
如果你想“编码高尔夫”,你可以在这里制作一些其他答案的简短版本:
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
但在我看来,真正理想的答案是使用Node的util库和它的promisify函数,它正是为这类事情而设计的(为先前存在的基于承诺的东西制作基于承诺的版本):
const util = require('util');
const sleep = util.promisify(setTimeout);
在任何一种情况下,你都可以使用await调用你的睡眠函数来暂停:
await sleep(1000); // sleep for 1s/1000ms
编辑:正如评论中所指出的,你甚至可以把它减少到一行:
const sleep = require('util').promisify(setTimeout);
或者,如果你甚至不想费心创建一个睡眠函数:
await require('util').promisify(setTimeout)(1000);
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
}
)
为了在javascript中“等待”,使用承诺是一种方法,正如上面的答案所示。
那么如何使用它呢?
下面是一个简单的例子,一个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'))