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

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

例子:

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

【问题讨论】:

    标签: javascript sleep


    【解决方案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://stackoverflow.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
                        }
                          
                      

                      【讨论】:

                        猜你喜欢
                        • 2011-06-15
                        • 1970-01-01
                        • 1970-01-01
                        • 2023-03-31
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多