js中怎么让程序暂停一段时间

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js中怎么让程序暂停一段时间相关的知识,希望对你有一定的参考价值。

参考技术A js不能直接让运行中的js代码停在某一步等待一段时间后继续向后执行。
但可以使用setTimeout或setInterval可以让js在需要的时候启动一个定时器。
需要延迟运行的代码放到setTimeout或setInterval块内即可。
如下代码即实现了类似功能

上面的脚本执行后,浏览器会依次弹出4个对话框,分别显示内容“现在开始运行程序脚本”,“脚本1”,“脚本2”,“脚本4”,当你点掉显示“脚本4”的对话框以后(尽量立即点掉),大约过10秒左右会弹出第五个“脚本3”的对话框。
另外,虽然while、if等以时间为条件的循环,强制执行死循环可以达到阻塞程序代码运行的目的,但会极大的消耗系统资源,一般开发程序是要严格避免这种方式的。

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

【中文标题】我如何在 Node.js (JavaScript) 中等待? l 需要暂停一段时间【英文标题】:How can I wait In Node.js (JavaScript)? l need to pause for a period of time 【发布时间】:2012-12-24 08:14:48 【问题描述】:

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

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

【问题讨论】:

@Christopher Allen,也许不相关,但确实有效:require("child_process").execSync('php -r "sleep($argv[1]);" ' + seconds); node-sleep npm 模块可以解决问题(但是,我只会将它用于调试) 这能回答你的问题吗? What is the JavaScript version of sleep()? 【参考方案1】:

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 中的和谐标志:https://nodejs.org/en/docs/es6/ 所有 NodeJS 版本供下载:https://nodejs.org/en/download/releases/

【讨论】:

我想你忘了sleep(1000)前面的await关键字 这确实应该是答案,sleep node.js 包会很麻烦。 let sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); 像我这样的oneliner怪胎:) let sleep = require('util').promisify(setTimeout); 适用于 Node 7.6+ 并提高了可读性 今天这救了我的培根(特别是@BrianHVB 发布的promisify 食谱)。【参考方案2】:

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

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

【讨论】:

“复杂的高度就是简单。” ——克莱尔·布斯·卢斯。这是迄今为止最好的答案,IMO。 这显然比其他答案更新得多,但它是 2018 年最优雅的,它可以在 1 行中完成工作,而不会对代码产生任何其他影响。 这个不错。您必须使用 NodeJS 7.6.0 或更高版本。它不适用于旧版本。 let sleep = require('util').promisify(setTimeout); 长三个字符但可重复使用且更易读 imo 为避免 eslint 投诉,请将其称为 resolve 而不是 done。 IE。 await new Promise(resolve => setTimeout(resolve, 5000))【参考方案3】:

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

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 的解决方案,但更简洁且更易于扩展。

【讨论】:

@LucasSeveryn 那么你做错了什么。这是一种核心设计模式。 而当函数的开始不只是一个函数,而是10个文件距离需要去异步的代码时,你会怎么做? @CyrilDuchon-Doris 什么? 使用@machineghost 的答案来获得一个优雅的基于承诺的解决方案,不需要自定义代码并支持等待/异步 这是异步的,这意味着如果function1在3秒之前终止,它们就会开始相互重叠。然后您甚至无法返回,并且几乎永远无法使用。到目前为止我发现的唯一方法是使用debugger;【参考方案4】:

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

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

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

【讨论】:

可怕与否,它做了一个简单的wait,它会阻塞并用于某些测试目的。正是我正在寻找的。​​span> 完美地回答了没有第三方库的问题,而且很简单。然而人们说“可怕”....这很好,例如用于模拟繁重的 CPU 负载等。顺便说一句,与 phpied.com/sleep-in-javascript 非常相似 这是spin-wait @Ali 这似乎是目标。 这是问题的唯一正确答案。 OP 专门要求调用一个等待函数,从该函数返回,然后继续。 (没有回调,没有任何异步,没有重写整个调用堆栈来处理承诺。)完全符合 OP 要求的唯一其他解决方案是调用外部程序,例如 Windows 上的 SLEEP.EXE【参考方案5】:

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

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

【讨论】:

这是非常混乱且通常不好的做法,特别是如果 OP 希望程序的其余部分在该延迟之后运行。看我的回答。 @ElliotBonneville 这只是一个说明这个概念的例子。显然,您可以(应该)将代码分解为函数调用,而不是像其他任何地方一样使用内联代码。 @ChristopherKemp:原来 Node.js 有一个解决方案,称为node-fibers。 Check it out. 这是一个很好的解决方案,特别是如果您不想执行任何代码,您只想在循环中模仿“睡眠”方法。这个例子没有错。 这非常适合延迟来自客户端的请求,我使用这种方法在客户端测试我的加载微调器【参考方案6】:

在节点 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
);

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

我想要一个在 Windows 和 Linux 中工作的异步睡眠,而不需要长时间的 while 循环占用我的 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

像魅力一样工作。

【讨论】:

很好的答案谢谢 - 它使一些不可能的代码成为可能 - 这不是旋转等待 在进一步的研究中,这个模块依赖于 deasync,它是从另一个 deasync github repo 派生的。原始回购警告不要使用它,因为它是一个黑客。它确实有效,但并非在所有平台上都有效,因此如果您需要跨平台解决方案,请避免使用此解决方案。 是的,我从来没有遇到过它的问题,而且它对开发人员来说非常有用——在幕后我相信它依赖于广泛可用的 C 或 C++,但我猜在某些机器上它不是,那是什么时候它失败了,这就是它导致问题的原因 - 如果它失败了,系统睡眠会退回到旋转等待,这将冻结代码执行 这个包不能在 Mac OS 上运行,因此不能交叉兼容,因此不能运行。见github.com/jochemstoel/nodejs-system-sleep/issues/4 @Nuzzolilo 这很奇怪。我们有一位 Mac OS 开发人员,他从未提到任何错误。我怀疑这是特定的 Mac OS 版本。我也更新了这个答案,因为 sleep 基本上内置在较新版本的 NodeJS 中。【参考方案7】:

使用现代 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 的睡眠函数,其他一切保持不变。不过async 可能更清楚。 很好,@KevinPeña。事实上,我想我更喜欢没有async。用你的建议编辑了我的答案。我认为它不会使代码更清晰;为此,我会改用 JSDoc。 我喜欢在我的脚本中使用以下单行:const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));【参考方案8】:

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

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

【讨论】:

它在MacOS 上运行良好,但由于node_gyp errors 而在CentOS 上遇到错误。它似乎不便携。 可能问题不是由操作系统引起的,而是由节点构建引起的 这是一项较新的功能,因此需要更新版本的 Node。【参考方案9】:

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

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

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

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

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

await require('util').promisify(setTimeout)(1000);

【讨论】:

实际上,使用 util.promisify,如果不提供回调,就无法调用 sleep。 nodejs.org/api/… 您缺少await。它有点创建回调,暂停事情,然后在回调返回时重新启动代码。回调返回一个值,但在这种情况下我们不关心它,所以await 的左侧没有任何内容。 把它写在一行中,让代码打高尔夫球;) const sleep = require('util').promisify(setTimeout); @F***,如果您只需要一次:await require('util').promisify(setTimeout)(1000);【参考方案10】:

这个问题已经很老了,但最近 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); 谢谢,@edhubbell。这个答案是基于一个非常旧版本的暂停,但你对最新版本是正确的。我会更新答案。 这是什么版本的节点? @danday74 我不记得它们是什么时候被取消标记的,但它们从 v0.12 开始就在 --harmony 标记后面,根据 node.green,它们是至少自 v4.8.4 以来没有任何标志可用:node.green/#ES2015-functions-generators-basic-functionality。但是请注意,较新的async/await 语法现在提供了更好的解决方案,不需要像suspend 这样的额外库。有关示例,请参见此答案:***.com/a/41957152/376789。自 v7.10 起,异步函数可用(无标志)。 这个很复杂as of 2021。【参考方案11】:

在 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'])【参考方案12】:

我最近创建了名为 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' 评论说:“//在 waitfor/paralell-tests.js 中定义”从该文件中获取它。 wait.for/paralell-tests.js 得到它后,我遇到了另一个与未定义属性等相关的错误。所以我也需要复制它们。为什么不以不需要的方式组织代码? Wait.for 和其他光纤解决方案为我打开了一个全新的世界!如果可以的话,我会投票一百万次。尽管大多数 nodejs 社区都反对纤程,但我认为它们是一个很棒的补充,并且在回调地狱中绝对占有一席之地。【参考方案13】:

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

所以 Node.js 紧随其后,

process.nextTick()

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

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

【讨论】:

【参考方案14】:

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

一个班轮

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

或将其作为NodeJS 中的函数重复使用

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

使用类似的功能

await sleep(5000)

【讨论】:

【参考方案15】:

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

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

【讨论】:

【参考方案16】:
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 中提取数据,并将解析后的数据传递回生成器。实际上,它使异步调用同步。

【讨论】:

虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。 谢谢@DonaldDuck。我回答中的代码可能是 Javascript 改进中最令人兴奋的部分。我很惊讶一些超级聪明的人会想到这种方法来解决回调地狱问题。【参考方案17】:

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

【讨论】:

【参考方案18】:

为了在 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'))

【讨论】:

【参考方案19】:

很简单,我们将等待 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;
        
    )();

【讨论】:

【参考方案20】:

对于某些人来说,接受的答案不起作用,我找到了另一个答案,它对我有用:How can I pass a parameter to a setTimeout() callback?

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

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

【讨论】:

【参考方案21】:
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
    
)

【讨论】:

【参考方案22】:

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

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

【讨论】:

【参考方案23】:

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

如果您真正想要的是降低 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 表示不缓冲输出。

【讨论】:

【参考方案24】:

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

function waitFor(ms, cb) 
  var waitTill = new Date(new Date().getTime() + ms);
  while(waitTill > new Date());
  if (cb) 
    cb()
   else 
   return true
  

【讨论】:

【参考方案25】:

更多信息

yield sleep(2000); 

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

【讨论】:

以上是关于js中怎么让程序暂停一段时间的主要内容,如果未能解决你的问题,请参考以下文章

如何让cmd命令暂停一段时间后再自动执行

如何让正在运行的线程暂停一段时间

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

pycharm定时停止运行

Linux命令之暂停一段时间sleep

2.1 暂停一段时间