如何在Node.js(JavaScript)中等待?我需要暂停一段时间

2020/09/28 00:41 · javascript ·  · 0评论

我正在开发满足个人需要的控制台脚本。我需要能够暂停很长一段时间,但是,根据我的研究,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无法识别这一点。

我如何实现这种长时间的暂停?

最好的方法是将代码分成多个功能,如下所示:

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的解决方案相似,但是更加整洁并且易于扩展。

对旧问题的新答案。今天(20171月,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开箱即用的功能而不安装和安装插件,必须使用带有--harmony标志的node-v7或node-v8

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

2020年5月更新:
不久您将能够在
await异步函数之外使用语法。在此示例的顶层

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

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

更多信息:

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

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

这是一种简单的阻止技术:

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

只要您的脚本中没有其他任何事情(例如回调),它就会阻塞但是由于这是一个控制台脚本,所以也许正是您所需要的!

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

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

在节点7.6.0或更高版本上

节点支持本地等待:

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
});

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

我希望在Windows和Linux中都能工作的异步睡眠,而又不会长时间占用CPU的时间。我尝试了睡眠程序包,但它不会安装在Windows机器上。我最终使用:

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

要安装它,请键入:

npm install system-sleep

在您的代码中

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

奇迹般有效。

使用现代Java脚本实现简单优雅的睡眠功能

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);
    });
}

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

您可以使用此www.npmjs.com/package/sleep

var sleep = require('sleep');
sleep.sleep(10); // sleep for ten seconds

This question is quite old, but recently V8 has added Generators which can accomplish what the OP requested. Generators are generally easiest to use for async interactions with the assistance of a library such as suspend or gen-run.

Here's an example using suspend:

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

Related reading (by way of shameless self promotion): What's the Big Deal with Generators?.

如果您想“编码高尔夫”,则可以在此处对其他一些答案进行简化:

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

但我认为,实际上,理想的答案是使用Node的util库及其promisify功能,该正是针对这种情况而设计的(制作先前存在的基于非承诺的东西的基于承诺的版本):

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

无论哪种情况,您都可以简单地通过使用await调用sleep函数暂停

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

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

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

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

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

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

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

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. 

同样,任何异步功能都可以在同步模式下调用检查示例。

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

因此,Node.js紧随其后,

process.nextTick()

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

process.nextTick(function(){
    console.log("This will be printed later");
});

有了ES6 support 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

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从异步调用中提取数据并将解析后的数据传递回生成器的机制。有效地,它使异步调用同步。

这是一个基于@ 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;

如果仅出于测试目的而需要暂停,请尝试执行以下操作:

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

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

    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;
        }
    })();

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

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

“ hello”是要传递的参数,您可以在超时时间之后传递所有参数。感谢@Fabio Phms的回答。

与其做所有这些setTimeout,sleep和许多其他事情,不如使用它

const delay = require('delay');
await delay(2000); // will wait for 2 seconds before executing next line of code
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
    }
)

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

如果您真正想要的只是降低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
  }
}

有关更多信息

yield sleep(2000); 

您应该检查Redux-Saga但这是特定于您选择Redux作为模型框架的(尽管绝对没有必要)。

本文地址:http://javascript.askforanswer.com/ruhezainode-jsjavascriptzhongdengdaiwoxuyaozantingyiduanshijian.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!