在 JavaScript 中休眠 - 动作之间的延迟

Posted

技术标签:

【中文标题】在 JavaScript 中休眠 - 动作之间的延迟【英文标题】:Sleep in JavaScript - delay between actions 【发布时间】:2010-10-20 00:15:17 【问题描述】:

有没有一种方法可以在 javascript 执行其他操作之前让其休眠?

例子:

 var a = 1+3;
 // Sleep 3 seconds before the next action here
 var b = a + 4;

【问题讨论】:

【参考方案1】:

你可以使用setTimeout来达到类似的效果:

var a = 1 + 3;
var b;
setTimeout(function() 
    b = a + 4;
, (3 * 1000));

这并不是真正的“睡眠”JavaScript——它只是在一定的持续时间(以毫秒为单位)后执行传递给setTimeout 的函数。虽然可以为 JavaScript 编写睡眠函数,但最好尽可能使用setTimeout,因为它不会在睡眠期间冻结所有内容。

【讨论】:

还可以查看 setInterval()。它类似于 setTimeout(),但你的函数被多次调用(直到你停止它),如果你想在睡觉时做一些事情(比如做进度更新、保持一些内部状态等等),这很有用。 这不能回答问题。这个问题要求一个“睡眠”等价物,这不是。 虽然这个答案与问题的答案不符,但它比循环和比较 Date.now() 更有用。没有人使用阻塞循环执行睡眠。 当然,除非阻塞循环正是有人想要的。【参考方案2】:

如果您真的需要 sleep() 来测试某些东西。但是请注意,它在调试时大多数时候都会使浏览器崩溃——这可能就是你需要它的原因。在生产模式下我会注释掉这个函数。

function pauseBrowser(millis) 
    var date = Date.now();
    var curDate = null;
    do 
        curDate = Date.now();
     while (curDate-date < millis);

不要在循环中使用new Date(),除非您想浪费内存、处理能力、电池以及可能的设备寿命。

【讨论】:

这个答案值得更多投票。为这个问题加注星标只是这个答案的原因。 @OkiErieRinaldi 那里没有递归,它只是一个循环。 @3.1415926535897932384626433833 好吧,有人要求提供“睡眠”功能,这就是这里。我用过一次,不记得具体是为了什么调试。如果我再次需要它,我知道在哪里可以找到它。如果您更喜欢其他功能,那是您的选择。能够选择是不是很棒? “正在等待”。 您一直在制造的忙碌等待循环完全符合您的期望:它将耗尽处理能力、电池,并可能耗尽您设备的使用寿命。它可能比new Date() 使用内存,但这也可能取决于实现。可以调试代码,甚至不要考虑将它用于任何中途生产的事情。【参考方案3】:

ECMAScript 6 版本,使用带有 yield 的生成器进行“代码阻塞”:

因为最初的问题是七年前发布的,所以我没有费心回答确切的代码,因为它太简单了而且已经回答了。这应该有助于解决更复杂的问题,例如您是否需要至少两次睡眠,或者您计划对异步执行进行排序。随意修改它以满足您的需求。

let sleeptime = 100
function* clock()

    let i = 0
    while( i <= 10000 )
    
        i++
        console.log(i); // actually, just do stuff you wanna do.
        setTimeout(
            ()=>
            
                clk.next()
            
            , sleeptime
        )
        yield
    


let clk = clock()
clk.next()

function*

() => arrow function

您也可以通过Promises链接事件:

function sleep(ms)

    return(
        new Promise(function(resolve, reject)
        
            setTimeout(function()  resolve(); , ms);
        )
    );



sleep(1000).then(function()

    console.log('1')
    sleep(1000).then(function()
    
        console.log('2')
    )
)

或者更简单、不那么花哨的方式

function sleep(ms, f)

    return(
        setTimeout(f, ms)
    )



sleep(500, function()

    console.log('1')
    sleep(500, function()
    
        console.log('2')
    )
)
console.log('Event chain launched')

如果你只是在等待某种情况发生,你可以这样等待

function waitTill(condition, thenDo)

    if (eval(condition))
    
        thenDo()
        return
    

    setTimeout(
        ()    =>
        
            waitTill(condition, thenDo)
        
        ,
        1
    )


x=0

waitTill(
    'x>2 || x==1'
    ,
    ()    =>
    
        console.log("Conditions met!")
    
)

// Simulating the change
setTimeout(
    () =>
    
        x = 1
    
    ,
    1000
)

【讨论】:

【参考方案4】:

如果您想要比setTimeoutsetInterval 更少笨重的函数,您可以将它们包装在只颠倒参数顺序并给它们起好名字的函数中:

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 毫秒,...”)

【讨论】:

【参考方案5】:

2018 年更新

最新的 Safari、Firefox 和 Node.js 现在也支持 async/await/promises。

使用 async/await/Promises:

(自 2017 年 1 月起,在 Chrome 上受支持,但在 Safari、Internet Explorer、Firefox、Node.js 上不支持)

'use strict';

function sleep(ms) 
  return new Promise(res => setTimeout(res, ms));


let myAsyncFunc = async function() 
  console.log('Sleeping');
  await sleep(3000);
  console.log('Done');


myAsyncFunc();

2017 年更新

自从提出这个问题以来,JavaScript 已经发展,现在有了生成器函数,并且正在推出新的 async/await/Promise。 下面有两种解决方案,一种具有适用于所有现代浏览器的生成器功能,另一种使用尚不支持的新 async/await。

使用生成器函数:

'use strict';

let myAsync = (g) => (...args) => 
    let f, res = () => f.next(),
        sleep = (ms) => setTimeout(res, ms);
    f = g.apply(sleep, args); f.next();
;

let myAsyncFunc = myAsync(function*() 
    let sleep = this;
    console.log("Sleeping");
    yield sleep(3000);
    console.log("Done");
);

myAsyncFunc();

请注意,这两种解决方案本质上都是异步的。这意味着 myAsyncFunc(在这两种情况下)将在睡眠时返回。

请务必注意,此问题不同于 What is the JavaScript version of sleep()?,其中请求者请求的是真正的睡眠(进程上没有其他代码执行),而不是动作之间的延迟。 p>

【讨论】:

迄今为止最好的答案!!我花了 30 分钟到处搜索以找到那个.. 非常感谢 !!! 我在寻找解决方案并重新发明了自行车时错过了这个答案:D 如果我能在它节省我几个小时之前看到它!点赞! let co = gen =&gt; (...args) =&gt; let iter = gen(...args); let resume = () =&gt; new Promise((resolve, reject) =&gt; let result = iter.next(); if (result.done) resolve(result.value); else Promise.resolve(result.value).then(resume).then(resolve, reject); ); return resume(); ; 会让您使用第二个代码块中的sleep() 定义来执行let asyncAdd = co(function* (a, b) console.log('Sleeping'); yield sleep(3000); console.log('Done'); return a + b; ); asyncAdd(3, 4).then(console.log);【参考方案6】:

有几种方法可以解决这个问题。如果我们使用setTimeout函数,我们先来了解一下。 This function 具有三个参数:functioncodedelay(以毫秒为单位)和 @987654327 @。 由于 functioncode 参数是必需的,因此其他参数是可选的。 一旦你没有输入延迟,它将被设置为零。

有关setTimeout()go to this link的更多详细信息。

简化版:

var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(function() 
    b = a + 4; 
    console.log('b = ' + b);
, 1000);

输出: a = 4 24       --> 活动超时列表的编号标识符 b = 8

使用参数传递:

var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(myFunction, 1000, a);

function myFunction(a)

    var b = a + 4;
    console.log('b = ' + b);

输出: a = 4 25       --> 活动超时列表的编号标识符 b = 8

浏览器支持:

Chrome 火狐边缘 Safari Opera 1.0 1.0 4.0 1.0 4.0

【讨论】:

【参考方案7】:

这是我的模型,展示了如何使用生成器函数 (ES6) 在 javascript 中“休眠”或“DoEvents”。注释代码:

<html>
<head>
<script>
  "use strict"; // always
  // Based on post by www-0av-Com https://***.com/questions/3143928
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
  var divelt, time0, globaln = 0; // global variables
  var MainGenObj = Main(); // generator object = generator function()
window.onload = function() 
  divelt = document.getElementsByTagName("body")[0]; // for addline()
  addline("typeof Main: " + typeof Main);
  addline("typeof MainDriver: " + typeof MainDriver);
  addline("typeof MainGenObj: " + typeof MainGenObj);
  time0 = new Date().valueOf(); // starting time ms
  MainDriver(); // do all parts of Main()

function* Main()  // this is "Main" -- generator function -- code goes here
  // could be loops, or inline, like this:

  addline("Part A, time: " + time() + ", " + ++globaln); // part A
  yield 2000;                    // yield for 2000 ms (like sleep)

  addline("Part B, time: " + time() + ", " +  ++globaln); // part B
  yield 3000;                    // yield for 3000 ms (or like DoEvents)

  addline("Part Z, time: " + time() + ", " +  ++globaln); // part Z (last part)
  addline("End, time: " + time());

function MainDriver()  // this does all parts, with delays
  var obj = MainGenObj.next(); // executes the next (or first) part of Main()
  if (obj.done == false)  // if "yield"ed, this will be false
    setTimeout(MainDriver, obj.value); // repeat after delay
  

function time()  // seconds from time0 to 3 decimal places
  var ret = ((new Date().valueOf() - time0)/1000).toString();
  if (ret.indexOf(".") == -1) ret += ".000";
  while (ret.indexOf(".") >= ret.length-3) ret += "0";
  return ret;

function addline(what)  // output
  divelt.innerHTML += "<br />\n" + what;

</script>
</head>
<body>
<button onclick="alert('I\'m alive!');"> Hit me to see if I'm alive </button>
</body>
</html>

【讨论】:

【参考方案8】:

另一种方法是使用 Promise 和 setTimeout(请注意,您需要在函数内部并使用 async 关键字将其设置为异步):

async yourAsynchronousFunction () 

    var a = 1+3;

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

    var b = a + 4;


【讨论】:

【参考方案9】:

您可以使用setTimeout在指定时间后调用回调:

setTimeout(() => 
    console.log('Called after 1 second');
, 1000);

如果你想使用setTimeout 作为一个承诺,你可以这样做:

const delay = milliseconds => new Promise(resolve =>  setTimeout(resolve, milliseconds); );

await delay(1000);

console.log('Called after 1 second');

从 Node.js 16 开始,这个功能也是built-in:

import setTimeout as delay from 'node:timers/promises';

await delay(1000);

console.log('Called after 1 second');

如果你想在 Node.js 或浏览器中在主线程之外实现同步延迟,you can use Atomics.wait:

const delay = milliseconds => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);

await delay(1000);

console.log('Called after 1 second');

【讨论】:

我喜欢它的优雅简洁。这是一条线。感人的。我送你一杯你选择的虚拟啤酒。 ?【参考方案10】:

这是一种非常简单的方法,它“感觉”像同步睡眠/暂停,但却是合法的 js 异步代码。

// Create a simple pause function
const pause = (timeoutMsec) => new Promise(resolve => setTimeout(resolve,timeoutMsec))

async function main () 
    console.log('starting');
    // Call with await to pause.  Note that the main function is declared asyc
    await pause(3*1000)
    console.log('done');

【讨论】:

【参考方案11】:

您可以使用纯 javascript,这将在 5 秒后调用您的函数/方法:

setTimeout(()=>  your_function(); , 5000);

【讨论】:

【参考方案12】:

这是一个使用调用 setTimeout() 的基于 Promise 的 sleep() 的重写和演示。它还演示了对 setTimeout() 的常规调用。

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


console.log("Synchronous call");
sleep(2000)
.then(() => console.log("Asynchronous call"));

Image of its run on Repl.it

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

console.log("Synchronous call 1");

sleep(4000)
 .then(() => console.log("Asynchronous call 1"));

sleep(2000)
 .then(() => console.log("Asynchronous call 2"));

console.log("Synchronous call 2");

sleep(3000)
 .then(() => console.log("Asynchronous call 3"));

console.log("Synchronous call 3");

sleep(5000)
 .then(() => console.log("Asynchronous call 4"))
 .then(
   sleep(7000)
    .then(()=>console.log("Asynchronous call 5"))
)

console.log("Synchronous call 4");

setTimeout(() => console.log("Asynchronous call 6"), 8000);
console.log("Synchronous call 5");

【讨论】:

【参考方案13】:

function delayer(ms)
  return new Promise((resolve, reject)=>
    setTimeout(()=>
      resolve();
    , ms)
  )


async function myFunction()  // Function Must be async.
  console.log("First Console")
  await delayer(2000);    // This Will Stop The Code For 2 Seconds
  console.log("Second Console")



myFunction()

【讨论】:

【参考方案14】:

物有所值

  isPause = true;
  setTimeout(()=>isPause=false,2000);
  while (!isPause) 
    // delay for 2 seconds
  
    

【讨论】:

以上是关于在 JavaScript 中休眠 - 动作之间的延迟的主要内容,如果未能解决你的问题,请参考以下文章

在线程池中休眠的线程

在执行过程中休眠一个线程

在 Swift 中休眠或延迟 Timer 线程

在批处理文件中休眠

在 Informix SPL 过程中休眠

为啥要在 bash 中休眠和等待?