有没有比下面的pausecomp函数(取自此处)更好的方法来设计JavaScript中的睡眠?

function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

这不是JavaScript中的Sleep的重复-动作之间的延迟;我希望在函数的中间有一个真正的睡眠,而不是在代码执行之前有一段延迟。


当前回答

一行使用Promise

const wait = t => new Promise(s => setTimeout(s, t, t));

带有中止信号的字体

const wait = (x: number, signal?: AbortSignal): Promise<number> => {
  return new Promise((s, f) => {
    const id = setTimeout(s, x, x);
    signal?.addEventListener('abort', () => {
      clearTimeout(id);
      f('AbortError');
    });
  });
};

Demo

const wait=t=>new Promise(s=>setTimeout(s,t));//用途异步函数demo(){//倒计时设i=6;而(i-){等待等待(1000);控制台日志(i);}//数字0到5的总和,延迟1秒constsum=await[…Array(6).keys()].reduce(async(a,b)=>{a=等待a;等待等待(1000);常量结果=a+b;console.log(`${a}+${b}=${result}`);返回结果;},承诺.决议(0));console.log(“sum”,总和);}demo();

其他回答

我认为这个问题很好,指出了重要的观点和考虑因素。

话虽如此,我认为问题的核心在于意图和理解开发人员(您)想要控制什么。

首先,名称sleep是一个重载的命名选择。即,“什么”将被“睡眠”;作为一名开发人员,我控制着什么?

在任何语言引擎中,在任何OS进程上运行,在任何裸机或托管系统上,“开发人员”都不控制(拥有)OS共享资源CPU内核(和/或线程),除非他们正在编写OS/process系统本身。CPU是一种时间共享资源,工作执行进度的货币是分配给系统上要执行的所有工作的“周期”。

作为一名应用程序/服务开发人员,最好考虑我是由操作系统进程/语言引擎管理的工作流活动流的控制者。在一些系统上,这意味着我控制一个本机os线程(可能共享CPU内核),在其他系统上,意味着我可以控制一个异步延续工作流链/树。

对于JavaScript,它是“后者”。

因此,当需要“睡眠”时,我打算让我的工作流在执行过程中“延迟”一段时间,然后再继续执行工作流中的下一个“步骤”(阶段/活动/任务)。

这是“恰当”的说法,即作为一个开发人员,最容易将模型作为线性代码流来工作;根据需要采用工作流的组合来进行缩放。

今天,在JavaScript中,我们可以选择使用高效的多任务20世纪80年代基于角色的延续架构(重新标记为现代Futures/Promises/then/await等)来设计这样的线性工作流。

考虑到这一点,我的答案不是提供新的技术解决方案,而是关注问题本身的意图和设计视角。

我建议,任何答案都要从思考上述概念开始,然后选择一个提醒和暗示意图的名字(而不是睡眠)。

工作流选择1:delayWorkForMs(nMsToDelay)选项2:delaySyncSequenceForMs(msPeriod)

async delayAsyncSequenceForMs(msPeriod) {
  await new Promise(resolve => setTimeout(resolve, msPeriod));
}

请记住,任何异步函数都会返回Promise,await只能在异步函数中使用。(哈哈,你可能会问自己为什么……)。注意事项1:不要使用“循环”来消耗cpu周期。注意事项2:在JavaScript模型中,当在非异步函数中时,您不能“延迟”(等待)“异步”工作流的执行(除非您正在做不必要的坏事,而不需要占用cpu周期)。您只能在“异步”函数中“延迟”代码步骤。在内部,“异步”函数被建模为每个await关键字处的入口点/延续的集合。如果您熟悉倒勾插值模型,您可以“将await”视为在概念上建模,类似于编写倒勾字符串,如:

  // Conceptualizing, using an interpolation example to illustrate
  // how to think about "await" and "async" functions
  `code${await then-restart-point}more-code${await then-restart-point}`

setTimeout是JavaScript异步方法的一部分(开始执行的方法,其结果将在将来某个时候返回到一个名为回调队列的组件,稍后将执行)

您可能想做的是将setTimeout函数包装在Promise中。

承诺示例:

constsleep=time=>newPromise(res=>setTimeout(res,time,“已完成睡眠”));//使用本机承诺sleep(2000).then(msg=>console.log(msg));

异步/等待示例:

constsleep=time=>newPromise(res=>setTimeout(res,time,“已完成睡眠”));//在顶层使用异步/等待(异步函数(){const msg=等待睡眠(2000);console.log(消息);})();

阅读有关setTimeout的更多信息

2017-2021更新

自2009年提出这个问题以来,JavaScript已经有了很大的发展。所有其他答案现在都过时或过于复杂。以下是当前的最佳实践:

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

或作为一个内衬:

await new Promise(r => setTimeout(r, 2000));

作为一项功能:

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

或使用字体:

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

将其用作:

await sleep(<duration>);

演示:

功能睡眠(ms){return new Promise(resol=>setTimeout(resolve,ms));}异步函数demo(){for(设i=0;i<5;i++){console.log(`等待${i}秒…`);等待睡眠(i*1000);}console.log('Done');}demo();

注意,

await只能在前缀为async关键字的函数中执行,或者在越来越多的环境中在脚本的顶层执行。await只暂停当前的异步函数。这意味着它不会阻止脚本的其余部分的执行,这在大多数情况下都是您想要的。如果您确实需要一个阻塞构造,请使用Atomics.wait查看这个答案,但请注意,大多数浏览器都不允许在浏览器的主线程上使用它。

两个新的JavaScript功能(截至2017年)帮助编写了这个“睡眠”函数:

Promises是ES2015(又称ES6)的原生功能。我们还在睡眠函数的定义中使用箭头函数。async/await特性允许代码显式地等待承诺(解决或拒绝)。

兼容性

承诺在Node v0.12+中得到支持,在浏览器中得到广泛支持,IE除外async/await登陆V8,自Chrome 55(2016年12月发布)以来默认启用它于2016年10月登陆Node 7并于2016年11月登陆Firefox Nightly

如果出于某种原因,您使用的Node早于7(已于2017年到期),或者针对的是旧浏览器,则仍可通过Babel(一种将JavaScript+新功能转换为普通旧JavaScript的工具)使用async/await,并使用将async-to-generator转换为生成器插件。

出于对$DEITY的热爱,请不要使用忙等待睡眠功能。setTimeout和setInterval可以满足您的需要。

var showHide=document.getElementById('showHide');setInterval(()=>{showHide.style.visibility=“初始”;setTimeout(()=>{showHide.style.visibility=“隐藏”}, 1000);}, 2000); <div id=“showHide”>您好!再见</分区>

每隔两秒隐藏文本一秒。这显示了如何使用setInterval和setTimeout每秒显示和隐藏文本。

如果你想要比setTimeout和setInterval更简单的函数,你可以将它们包装在函数中,只需颠倒参数的顺序,给它们起个好听的名字:

function after(ms, fn){ setTimeout(fn, ms); }
function every(ms, fn){ setInterval(fn, ms); }

CoffeeScript版本:

after = (ms, fn)-> setTimeout fn, ms
every = (ms, fn)-> setInterval fn, ms

然后,您可以将它们很好地用于匿名函数:

after(1000, function(){
    console.log("it's been a second");
    after(1000, function(){
        console.log("it's been another second");
    });
});

现在它很容易读成“N毫秒后,…”(或“每N毫秒,…”)