sleep()的javascript版本是什么?

What is the JavaScript version of sleep()?

在javascript中,有没有比下面的pausecomp函数更好的方法来设计sleep

1
2
3
4
5
6
7
function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

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


2017更新

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

1
2
3
4
5
6
7
8
9
10
11
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
  console.log('Taking a break...');
  await sleep(2000);
  console.log('Two seconds later');
}

demo();

就是这样。await sleep()

您可以在runkit上尝试此代码。请注意,

  • await只能在前缀为async关键字的函数中执行。runkit在执行代码之前将代码包装在异步函数中。
  • await只暂停当前的async功能。
  • 两个新的javascript功能帮助编写了这个实际的"睡眠"功能:

    • Promises,ES2015的本土特色(又称ES6)。我们在睡眠功能的定义中也使用了箭头函数。
    • 即将推出的async/await特性允许代码明确地等待承诺的解决。

    兼容性

    • 承诺在节点v0.12+中得到支持,在浏览器中得到广泛支持,IE除外。
    • async/await降落在V8上,从chrome 55开始默认启用。
      • 2016年10月登陆节点7
      • 并于2016年11月登陆了Firefox Nightly。

    如果出于某种原因,您使用的节点早于7,或者针对的是旧的浏览器,那么仍然可以通过babel(一种将javascript+新功能开发为普通的旧javascript的工具)和transform-async-to-generator插件来使用async/await。跑

    1
    npm install babel-cli --save

    创建.babelrc时使用:

    1
    2
    3
    4
    5
    {
     "plugins": [
       "transform-async-to-generator",
      ]
    }

    然后用运行代码

    1
    node_modules/babel-cli/bin/babel-node.js sleep.js

    但同样,如果您使用的是节点7或更高版本,或者您的目标是现代浏览器,则不需要这样做。


    (见2016年更新答案)

    我认为想要执行一个动作,等待,然后再执行另一个动作是完全合理的。如果您习惯于用多线程语言编写,那么您可能会有一个想法,在线程唤醒之前,在一定的时间内生成执行。

    这里的问题是javascript是一个基于单线程事件的模型。在特定情况下,让整个引擎等待几秒钟可能会比较好,一般来说这是不好的做法。假设我想在编写自己的函数时使用您的函数?当我调用你的方法时,我的方法都会冻结。如果javascript可以以某种方式保留函数的执行上下文,将其存储在某个地方,然后将其恢复并在稍后继续,那么可能会发生睡眠,但这基本上就是线程化。

    因此,您基本上坚持了其他人的建议——您需要将代码分解成多个函数。

    那么,你的问题是一个错误的选择。没有办法按照你想要的方式睡觉,你也不应该追求你建议的解决方案。


    在javascript中,我重写了每个函数,以便它能够尽快结束。您希望浏览器回到控件中,这样它可以更改您的DOM。

    每次我想要在函数的中间休息时,我都重构为使用setTimeout()

    I am going to edit this answer because i found this as useful:

    在任何一种语言中,臭名昭著的睡眠,或者说是延迟,其功能都备受争议。有些人会说,应该总是有一个信号或回调来触发一个给定的功能,另一些人会说,有时一个任意的延迟时间是有用的。我要说的是,在这个行业中,每个人都有自己的一条规则,不能支配任何东西。

    编写sleep函数很简单,而且在javascript承诺下更加有用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // sleep time expects milliseconds
    function sleep (time) {
      return new Promise((resolve) => setTimeout(resolve, time));
    }

    // Usage!
    sleep(500).then(() => {
        // Do something after the sleep!
    });


    仅用于调试/dev,如果它对某人有用,我会发布它

    有趣的是,在Firebug(可能是其他JS控制台)中,只有在指定的睡眠时间(…)之后,才会在按Enter键后发生任何事情。

    1
    2
    3
    4
    function sleepFor( sleepDuration ){
        var now = new Date().getTime();
        while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
    }

    使用实例:

    1
    function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }


    我同意其他的海报,忙碌的睡眠只是个坏主意。

    但是,setTimeout不会延迟执行,它会在设置超时后立即执行函数的下一行,而不是在超时到期后执行,这样就不会完成与sleep将完成的任务相同的任务。

    这样做的方法是将您的功能分解为前后部分。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function doStuff()
    {
      //do some things
      setTimeout(continueExecution, 10000) //wait ten seconds before continuing
    }

    function continueExecution()
    {
       //finish doing things after the pause
    }

    确保您的函数名仍然准确地描述了每一项正在执行的操作(即gathereinputhenwait和checkinput,而不是funcpart1和funcpart2)

    编辑

    这种方法的目的是在超时之后才执行您决定的代码行,同时仍然将控制权返回到客户机PC以执行它排队等待的任何其他操作。

    进一步编辑

    正如评论中指出的,这绝对不会在循环中工作。你可以做一些奇特的(丑陋的)黑客行为,使它在一个循环中工作,但一般来说,这只会造成灾难性的意大利面条代码。


    为了$DEITY的爱,请不要做忙碌的等待睡眠功能。setTimeoutsetInterval做你需要的一切。


    我知道这是一个古老的问题,但是如果(像我一样)你在Rhino中使用JavaScript,你可以使用…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    try
    {
      java.lang.Thread.sleep(timeInMilliseconds);
    }
    catch (e)
    {
      /*
       * This will happen if the sleep is woken up - you might want to check
       * if enough time has passed and sleep again if not - depending on how
       * important the sleep time is to you.
       */

    }


    如果您使用jquery,实际上有人创建了一个"延迟"插件,它只不过是一个用于设置超时的包装器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Delay Plugin for jQuery
    // - http://www.evanbot.com
    // - ? 2008 Evan Byrne

    jQuery.fn.delay = function(time,func){
        this.each(function(){
            setTimeout(func,time);
        });

        return this;
    };

    然后您可以在一行函数调用中按预期使用它:

    1
    2
    3
    4
    $('#warning')
    .addClass('highlight')
    .delay(1000)
    .removeClass('highlight');


    我也搜索过睡眠解决方案(不用于生产代码,仅用于开发/测试),并找到了这篇文章:

    http://narayanraman.blogspot.com/2005/12/javascript-sleep-or-wait.html

    …下面是另一个与客户端解决方案的链接:http://www.devcasider.com/

    另外,当您调用alert()时,您的代码也将暂停,同时显示警报——需要找到一种方法来不显示警报,但获得相同的效果。:)


    干得好。正如代码所说,不要做一个坏的开发人员,在网站上使用它。它是一个开发效用函数。

    1
    2
    3
    4
    5
    6
    // Basic sleep function based on ms.
    // DO NOT USE ON PUBLIC FACING WEBSITES.
    function sleep(ms) {
        var unixtime_ms = new Date().getTime();
        while(new Date().getTime() < unixtime_ms + ms) {}
    }


    下面是一个使用同步xmlhttpRequest的简单解决方案:

    1
    2
    3
    4
    5
    function sleep(n){
      var request = new XMLHttpRequest();
      request.open('GET', '/sleep.php?n=' + n, false);  // `false` makes the request synchronous
      request.send(null);
    }

    sleep.php的内容:

    1
    <?php sleep($_GET['n']);

    现在,请使用:睡眠(5);


    第一:

    定义要执行的函数,如下所示:

    1
    2
    3
    function alertWorld(){
      alert("Hello World");
    }

    然后使用setTimeout方法计划其执行:

    1
    setTimeout(alertWorld,1000)

    注意两件事

    • 第二个参数是时间(毫秒)
    • 作为第一个参数,您必须只传递函数的名称(引用),而不传递括号

    我个人喜欢简单的:

    1
    2
    3
    4
    function sleep(seconds){
        var waitUntil = new Date().getTime() + seconds*1000;
        while(new Date().getTime() < waitUntil) true;
    }

    然后:

    1
    sleep(2); // Sleeps for 2 seconds

    在p5js中创建脚本时,我一直在使用它来创建假加载时间。


    让事情看起来像大多数人想要的更好的解决方案是使用匿名函数:

    1
    2
    3
    4
    5
    6
    7
    alert('start');
    var a = 'foo';
    //lots of code
    setTimeout(function(){  //Beginning of code that should run AFTER the timeout
        alert(a);
        //lots more code
    },5000);  // put the timeout here

    这可能是你最接近做你想做的事情。

    注意,如果你需要多个睡眠,这可能会在匆忙中变得难看,你可能实际上需要重新考虑你的设计。


    我将把setTimeout封装在与其他异步任务的代码一致性承诺中:fiddle中的demo

    1
    2
    3
    4
    5
    6
    function sleep(ms)
    {
        return(new Promise(function(resolve, reject) {        
            setTimeout(function() { resolve(); }, ms);        
        }));    
    }

    使用方法如下:

    1
    2
    3
    sleep(2000).then(function() {
       // Do something
    });

    如果你使用承诺,很容易记住语法。


    对于浏览器,我同意setTimeout和setInterval是一种方法。

    但是对于服务器端代码,它可能需要一个阻塞函数(例如,这样您就可以有效地进行线程同步)。

    如果您使用node.js和meetor,那么可能会遇到在光纤中使用setTimeout的限制。这是服务器端睡眠的代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    var Fiber = require('fibers');

    function sleep(ms) {
        var fiber = Fiber.current;
        setTimeout(function() {
            fiber.run();
        }, ms);
        Fiber.yield();
    }

    Fiber(function() {
        console.log('wait... ' + new Date);
        sleep(1000);
        console.log('ok... ' + new Date);
    }).run();
    console.log('back in main');

    请参阅:https://github.com/laverdet/node fibers sleep


    这里的大多数答案都是错误的,或者至少是过时的。没有理由让javascript必须是单线程的,事实上并非如此。如今,所有主流浏览器都支持工作人员,而其他的javascript运行时(如rhino和node.js)都支持多线程。

    "javascript是单线程的"不是有效答案。例如,在工作线程中运行sleep函数不会阻塞在UI线程中运行的任何代码。

    在支持生成器和yield的较新运行时中,可以在单线程环境中为sleep函数带来类似的功能:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // This is based on the latest ES6 drafts.
    // js 1.7+ (SpiderMonkey/Firefox 2+) syntax is slightly different

    // run code you want to sleep here (ommit star if using js 1.7)
    function* main(){
        for (var i = 0; i < 10; i++) {
            // to sleep for 10 milliseconds 10 times in a row
            yield 10;
        }

        yield 5;
        console.log('I just slept 5 milliseconds!');
    }

    // resume the given generator after ms milliseconds
    function resume(ms, generator){
        setTimeout(function(){
            // ommit .value if using js 1.7
            var nextSleep = generator.next().value;
            resume(nextSleep, generator);
        }, ms);
    }

    // initialize generator and get first sleep for recursive function
    var
        generator = main(),
        firstSleep = generator.next().value;

    // initialize recursive resume function
    resume(firstSleep, generator);

    这种对睡眠的模仿不同于真正的睡眠功能,因为它不会阻塞线程。它只是Javascript当前setTimeout函数的基础。这种功能类型已经在task.js中实现,现在应该可以在firefox中使用。


    1
    2
    3
    4
    5
    6
    7
    8
    function sleep(milliseconds) {
      var start = new Date().getTime();
      for (var i = 0; i < 1e7; i++) {
        if ((new Date().getTime() - start) > milliseconds){
          break;
        }
      }
    }


    我在javascript sleep/wait上搜索了很多网页。如果你想让javascript"运行,延迟,运行"…大多数人得到的不是"跑,跑(无用的东西),跑"就是"跑,跑+延迟跑"……

    所以我吃了些汉堡然后想:这是一个可行的解决方案…但是你必须把你的运行代码切碎……::是的,我知道,这只是一个更容易阅读的重构…还是…

    //………………………………//示例1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    <html>
    <body>
    DISPLAY


    //javascript sleep by"therealdealsince1982"; copyrighted 2009
    //setInterval
    var i = 0;

    function run() {
        //pieces of codes to run
        if (i==0){document.getElementById("id1").innerHTML="<p>
    code segment"
    + i +" is ran
    </p>"
    ; }
        if (i==1){document.getElementById("id1").innerHTML="<p>
    code segment"
    + i +" is ran
    </p>"
    ; }
        if (i==2){document.getElementById("id1").innerHTML="<p>
    code segment"
    + i +" is ran
    </p>"
    ; }
        if (i >2){document.getElementById("id1").innerHTML="<p>
    code segment"
    + i +" is ran
    </p>"
    ; }
        if (i==5){document.getElementById("id1").innerHTML="<p>
    all code segment finished running
    </p>"
    ; clearInterval(t); } //end interval, stops run
        i++; //segment of code finished running, next...
    }

    run();
    t=setInterval("run()",1000);


    </body>
    </html>

    //………………………………//示例2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    <html>
    <body>
    DISPLAY


    //javascript sleep by"therealdealsince1982"; copyrighted 2009
    //setTimeout
    var i = 0;

    function run() {
        //pieces of codes to run, can use switch statement
        if (i==0){document.getElementById("id1").innerHTML="<p>
    code segment"
    + i +" ran
    </p>"
    ; sleep(1000);}
        if (i==1){document.getElementById("id1").innerHTML="<p>
    code segment"
    + i +" ran
    </p>"
    ; sleep(2000);}
        if (i==2){document.getElementById("id1").innerHTML="<p>
    code segment"
    + i +" ran
    </p>"
    ; sleep(3000);}
        if (i==3){document.getElementById("id1").innerHTML="<p>
    code segment"
    + i +" ran
    </p>"
    ;} //stops automatically
        i++;
    }

    function sleep(dur) {t=setTimeout("run()",dur);} //starts flow control again after dur

    run(); //starts

    </body>
    </html>

    //………………例3:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    <html>
    <body>
    DISPLAY


    //javascript sleep by"therealdealsince1982"; copyrighted 2009
    //setTimeout
    var i = 0;

    function flow() {
        run(i);
        i++; //code segment finished running, increment i; can put elsewhere
        sleep(1000);
        if (i==5) {clearTimeout(t);} //stops flow, must be after sleep()
    }

    function run(segment) {
        //pieces of codes to run, can use switch statement
        if (segment==0){document.getElementById("id1").innerHTML="<p>
    code segment"
    + segment +" is ran
    </p>"
    ; }
        if (segment==1){document.getElementById("id1").innerHTML="<p>
    code segment"
    + segment +" is ran
    </p>"
    ; }
        if (segment==2){document.getElementById("id1").innerHTML="<p>
    code segment"
    + segment +" is ran
    </p>"
    ; }
        if (segment >2){document.getElementById("id1").innerHTML="<p>
    code segment"
    + segment +" is ran
    </p>"
    ; }
    }

    function sleep(dur) {t=setTimeout("flow()",dur);} //starts flow control again after dur

    flow(); //starts flow

    </body>
    </html>

    //第……页例4:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    <html>
    <body>
    DISPLAY


    //javascript sleep by"therealdealsince1982"; copyrighted 2009
    //setTimeout, switch
    var i = 0;

    function flow() {
        switch(i)
        {
            case 0:
                run(i);
                sleep(1000);
                break;
            case 1:
                run(i);
                sleep(2000);
                break;
            case 5:
                run(i);
                clearTimeout(t); //stops flow
                break;
            default:
                run(i);
                sleep(3000);
                break;
        }
    }

    function run(segment) {
        //pieces of codes to run, can use switch statement
        if (segment==0){document.getElementById("id1").innerHTML="<p>
    code segment"
    + segment +" is ran
    </p>"
    ; }
        if (segment==1){document.getElementById("id1").innerHTML="<p>
    code segment"
    + segment +" is ran
    </p>"
    ; }
        if (segment==2){document.getElementById("id1").innerHTML="<p>
    code segment"
    + segment +" is ran
    </p>"
    ; }
        if (segment >2){document.getElementById("id1").innerHTML="<p>
    code segment"
    + segment +" is ran
    </p>"
    ; }
        i++; //current segment of code finished running, next...
    }

    function sleep(dur) {t=setTimeout("flow()",dur);} //starts flow control again after dur

    flow(); //starts flow control for first time...

    </body>
    </html>


    您可能需要sleep()函数而不是使用setTimeout()的一种情况是,如果您有一个函数响应用户单击,最终将打开一个新的弹出窗口,并且您已经启动了一些处理,需要很短时间才能完成弹出窗口的显示。将打开的窗口移动到关闭状态意味着它通常会被浏览器阻止。


    加上我的两位。为了测试的目的,我需要一个忙碌的等待。我不想分割代码,因为这将是一个很大的工作,所以一个简单的为我做。

    1
    2
    3
    for (var i=0;i<1000000;i++){                    
         //waiting
      }

    我不认为这样做有什么坏处,这对我有好处。


    它可以使用Java的睡眠方法来完成。我已经在FF和IE中测试过它,它不会锁定计算机,不会占用资源,也不会导致无休止的服务器点击。对我来说似乎是一个干净的解决方案。

    首先,必须让Java加载到页面上并使其方法可用。为此,我做到了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <html>
    <head>

    <script type="text/javascript">

      function load() {
        var appletRef = document.getElementById("app");
        window.java = appletRef.Packages.java;
      } // endfunction



    <body onloadx="load()">

    然后,当您想要在JS中无痛暂停时,您所要做的就是:

    1
    java.lang.Thread.sleep(xxx)

    其中,xxx是以毫秒为单位的时间。在我的例子中(通过证明),这是一家非常小的公司后端订单履行的一部分,我需要打印一张必须从服务器加载的发票。我是通过将发票(作为网页)加载到iframe中,然后打印iframe来完成的。当然,我必须等到页面完全加载之后才能打印,所以JS必须暂停。我通过让发票页(在iframe中)用onload事件更改父页上的隐藏表单字段来完成这项工作。打印发票的父页上的代码如下(为了清晰起见,不相关的部分被剪切):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var isReady = eval('document.batchForm.ready');
    isReady.value=0;

    frames['rpc_frame'].location.href=url;

    while (isReady.value==0) {
      java.lang.Thread.sleep(250);
    } // endwhile

    window.frames['rpc_frame'].focus();
    window.frames['rpc_frame'].print();

    因此,用户按下按钮,脚本加载发票页面,然后等待,每季度检查一次发票页面是否完成加载,然后弹出打印对话框,供用户将其发送到打印机。QED。


    如果必须处理同步执行,我可以理解sleep函数的用途。setInterval和setTimeout函数创建一个并行执行线程,该线程将执行序列返回到主程序,如果必须等待给定的结果,则该线程无效。当然,可以使用事件和处理程序,但在某些情况下,这并不是预期的。


    很多答案不能(直接)回答这个问题,这个也不能…

    这是我的两分钱(或函数):

    如果您想要的函数比setTimeoutsetInterval要小一些,您可以将它们包装成与参数顺序相反的函数,并给它们起好的名称:

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

    咖啡说明版本:

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

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

    1
    2
    3
    4
    5
    6
    after(1000, function(){
        console.log("it's been a second");
        after(1000, function(){
            console.log("it's been another second");
        });
    });

    现在,它很容易读取为"n毫秒之后,…"(或"每隔n毫秒,………")


    对于希望将循环执行的一组调用隔开的特定情况,您可以在原型中使用类似下面的代码。如果没有原型,可以用setTimeout替换delay函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function itemHandler(item)
    {
        alert(item);
    }

    var itemSet = ['a','b','c'];

    // Each call to itemHandler will execute
    // 1 second apart
    for(var i=0; i<itemSet.length; i++)
    {
        var secondsUntilExecution = i;
        itemHandler.delay(secondsUntilExecution, item)
    }

    如果您在node.js上,可以查看fibers——节点的本机C扩展,类似于多线程模拟。

    它允许您以一种在光纤中阻塞执行的方式执行真正的sleep,但它在主线程和其他光纤中是非阻塞的。

    以下是他们自述的一个新例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // sleep.js

    var Fiber = require('fibers');

    function sleep(ms) {
        var fiber = Fiber.current;
        setTimeout(function() {
            fiber.run();
        }, ms);
        Fiber.yield();
    }

    Fiber(function() {
        console.log('wait... ' + new Date);
        sleep(1000);
        console.log('ok... ' + new Date);
    }).run();
    console.log('back in main');

    -结果是:

    1
    2
    3
    4
    $ node sleep.js
    wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
    back in main
    ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)

    2009年的老问题。现在,在2015年,一个新的解决方案可能与ECMAScript 2015又名ES6中定义的发电机一起使用。它在6月份得到了批准,但以前在火狐和Chrome中实现过。现在,一个睡眠函数可以在不冻结浏览器的情况下,在循环和子函数中实现非忙、非阻塞和嵌套。只需要纯JavaScript,不需要库或框架。

    下面的程序显示了如何制作sleep()runSleepyTask()sleep()函数只是yield语句。简单到直接编写yield语句而不是调用sleep(),但是没有sleep word:-)yield返回一个时间值给wakeup()内的next()方法等待。实际的"睡眠"是在wakeup()中用老的setTimeout()来完成的。在回调时,next()方法触发yield语句继续,而yield的"魔力"是所有局部变量和它周围的整个调用堆栈仍然是完整的。

    使用sleep()或yield的函数必须定义为生成器。在关键字function*中添加asterix很容易。执行一个生成器有点棘手。使用关键字new调用时,生成器返回一个对象,该对象具有next()方法,但不执行生成器体(关键字new是可选的,没有区别)。next()方法触发执行发生器主体,直到遇到yield为止。包装函数runSleepyTask()启动乒乓:next()等待yieldyield等待next()

    调用生成器的另一种方法是使用关键字yield*,这里它的工作方式类似于一个简单的函数调用,但它还包括返回next()的能力。

    这一切都由示例drawTree()证明。它在旋转的三维场景中绘制一棵有树叶的树。一棵树被画成树干,顶部有三部分朝着不同的方向生长。然后,在短暂的睡眠后,通过递归地调用drawTree(),将每个部分绘制为另一个较小的树。一棵非常小的树被画成一片叶子。

    每片叶子都有自己的生命在一个独立的任务中,这个任务从runSleepyTask()开始。它在以东地生、长、坐、消、落、死。速度由sleep()控制。这表明多任务处理是多么简单。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    function* sleep(milliseconds) {yield milliseconds};

    function runSleepyTask(task) {
        (function wakeup() {
            var result = task.next();
            if (!result.done) setTimeout(wakeup, result.value);
        })()
    }
    //////////////// written by Ole Middelboe  /////////////////////////////

    pen3D =setup3D();
    var taskObject = new drawTree(pen3D.center, 5);
    runSleepyTask(taskObject);

    function* drawTree(root3D, size) {
        if (size < 2) runSleepyTask(new growLeaf(root3D))
        else {
            pen3D.drawTrunk(root3D, size);
            for (var p of [1, 3, 5]) {
                var part3D = new pen3D.Thing;
                root3D.add(part3D);
                part3D.move(size).turn(p).tilt(1-p/20);
                yield* sleep(50);
                yield* drawTree(part3D, (0.7+p/40)*size);
            }
        }
    }

    function* growLeaf(stem3D) {
        var leaf3D = pen3D.drawLeaf(stem3D);
        for (var s=0;s++<15;) {yield* sleep(100); leaf3D.scale.multiplyScalar(1.1)}
        yield* sleep( 1000 + 9000*Math.random() );
        for (var c=0;c++<30;) {yield* sleep(200); leaf3D.skin.color.setRGB(c/30, 1-c/40, 0)}
        for (var m=0;m++<90;) {yield* sleep( 50); leaf3D.turn(0.4).tilt(0.3).move(2)}
        leaf3D.visible = false;
    }
    ///////////////////////////////////////////////////////////////////////

    function setup3D() {
        var scene, camera, renderer, diretionalLight, pen3D;

        scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera(75,
            window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 15, 20);
        renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
       
        directionalLight = new THREE.DirectionalLight(0xffffaa, 0.7);
        directionalLight.position.set(-1, 2, 1);
        scene.add(directionalLight);
        scene.add(new THREE.AmbientLight(0x9999ff));
         
        (function render() {
            requestAnimationFrame(render);
            // renderer.setSize( window.innerWidth, window.innerHeight );
            scene.rotateY(10/60/60);
            renderer.render(scene, camera);
        })();
       
        window.addEventListener(
            'resize',
            function(){
                renderer.setSize( window.innerWidth, window.innerHeight );
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
           },
           false
        );
       
        pen3D = {
            drawTrunk: function(root, size) {
                // root.skin = skin(0.5, 0.3, 0.2);
                root.add(new THREE.Mesh(new THREE.CylinderGeometry(size/12, size/10, size, 16),
                    root.skin).translateY(size/2));
                root.add(new THREE.Mesh(new THREE.SphereGeometry(size/12, 16),
                    root.skin).translateY(size));
                return root;
            },
           
            drawLeaf: function(stem) {
                stem.skin.color.setRGB(0, 1, 0);
                stem.add(new THREE.Mesh(new THREE.CylinderGeometry(0, 0.02, 0.6),
                    stem.skin) .rotateX(0.3).translateY(0.3));
                stem.add(new THREE.Mesh(new THREE.CircleGeometry(0.2),
                    stem.skin) .rotateX(0.3).translateY(0.4));
                return stem;
            },
           
            Thing: function() {
                THREE.Object3D.call(this);
                this.skin = new THREE.MeshLambertMaterial({
                    color: new THREE.Color(0.5, 0.3, 0.2),
                    vertexColors: THREE.FaceColors,
                    side: THREE.DoubleSide
                })
            }
        };

        pen3D.Thing.prototype = Object.create(THREE.Object3D.prototype);
        pen3D.Thing.prototype.tilt = pen3D.Thing.prototype.rotateX;
        pen3D.Thing.prototype.turn = pen3D.Thing.prototype.rotateY;
        pen3D.Thing.prototype.move = pen3D.Thing.prototype.translateY;
       
        pen3D.center = new pen3D.Thing;
        scene.add(pen3D.center);
       
        return pen3D;
    }
    1
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js">

    3D文件隐藏在setup3d()中,只是为了使它比console.log()更不无聊。顺便说一下,天使是以弧度来衡量的。

    在火狐和Chrome上测试过。未在Internet Explore和iOS(iPad)中实现。试着自己跑。

    在我找到另一个答案之后,加布里埃尔·拉特纳一年前也给出了类似的答案:https://stackoverflow.com/a/24401317/5032384


    在javascript中,您不能这样睡眠,或者更确切地说,您不应该这样睡眠。运行sleep或while循环将导致用户的浏览器挂起,直到循环完成。

    使用计时器,如您引用的链接中指定的。


    如果你是这样的睡眠功能

    1
    2
    3
    4
    5
    6
    7
    8
    var sleep = function(period, decision, callback){
        var interval = setInterval(function(){
            if (decision()) {
                interval = clearInterval(interval);
                callback();
            }
        }, period);
    }

    您有一个异步函数可以多次调用

    1
    2
    3
    4
    var xhr = function(url, callback){
        // make ajax request
        // call callback when request fulfills
    }

    您的项目设置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var ready = false;

    function xhr1(){
        xhr(url1, function(){ ready = true;});  
    }
    function xhr2(){
        xhr(url2, function(){ ready = true; });
    }
    function xhr3(){
        xhr(url3, function(){ ready = true; });
    }

    然后你可以这样做:

    1
    2
    3
    4
    5
    6
    xhr1();
    sleep(100, function(){ return done; }, xhr2);
    sleep(100, function(){ return done; }, xhr3);
    sleep(100, function(){ return done; }, function(){
        // do more
    });

    而不是像这样没完没了的回调缩进:

    1
    2
    3
    4
    5
    6
    7
    xhr(url1, function(){
        xhr2(url2, function(){
            xhr3(url3, function(){
                // do more
            });
        });
    });

    从这个链接中获取的代码不会冻结comp。但它只在FF上工作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    /**
     * Netscape compatible WaitForDelay function.
     * You can use it as an alternative to Thread.Sleep() in any major programming language
     * that support it while JavaScript it self doesn't have any built-in function to do such a thing.
     * parameters:
     * (Number) delay in millisecond
     */

    function nsWaitForDelay(delay) {
        /**
         * Just uncomment this code if you're building an extention for Firefox.
         * Since FF3, we'll have to ask for user permission to execute XPCOM objects.
         */

        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

        // Get the current thread.
        var thread = Components.classes["@mozilla.org/thread-manager;1"].getService(Components.interfaces.nsIThreadManager).currentThread;

        // Create an inner property to be used later as a notifier.
        this.delayed = true;

        /* Call JavaScript setTimeout function
          * to execute this.delayed = false
          * after it finish.
          */

        setTimeout("this.delayed = false;", delay);

        /**
         * Keep looping until this.delayed = false
         */

        while (this.delayed) {
            /**
             * This code will not freeze your browser as it's documented in here:
             * https://developer.mozilla.org/en/Code_snippets/Threads#Waiting_for_a_background_task_to_complete
             */

            thread.processNextEvent(true);
        }
    }

    首先,应该使用setTimeout和setInterval,因为javascript具有回调特性。如果您想使用sleep(),那么您的代码的控制流或体系结构是不正确的。

    我已经说过了,我想我仍然可以帮助实现两个睡眠。

  • 假同步跑出我的头顶:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //a module to do taht //dual-license: MIT or WTF [you can use it anyhow and leave my nickname in a comment if you want to]
    var _=(function(){
     var queue=[];
     var play=function(){
       var go=queue.shift();
         if(go){if(go.a){go.f();play();}else{setTimeout(play,go.t);}}
       }
     return {
       go:function(f){
        queue.push({a:1,f:f});
        },
       sleep:function(t){
        queue.push({a:0,t:t});
        },
       playback:play
     }
    })();

    [也可以自动播放]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //usage

    _.go(function(){

    //your code
    console.log('first');

    });


    _.sleep(5000);

    _.go(function(){

    //your code
    console.log('next');

    });

    //this triggers the simulation
    _.playback();
  • 实同步运行

  • 有一天我仔细考虑了一下,我在javascript中真正睡着的唯一想法是技术上的。

    sleep函数必须是一个同步的Ajax调用,并将超时设置为sleep值。只有这样才能拥有真正的EDOCX1[1]


    由于节点7.6,您可以将来自utils模块的promisify功能与setTimeout结合起来。

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

    一般用法

    1
    2
    3
    4
    5
    6
    7
    async function main() {
        console.time("Slept for")
        await sleep(3000)
        console.timeEnd("Slept for")
    }

    main()

    问题用法

    1
    2
    3
    4
    5
    6
    7
    async function asyncGenerator() {
        while (goOn) {
          var fileList = await listFiles(nextPageToken);
          await sleep(3000)
          var parents = await requestParents(fileList);
        }
      }

    万一你真的需要一个sleep()来测试一些东西。但是请注意,在调试的时候,大多数时候浏览器都会崩溃——这可能就是为什么你无论如何都需要它。在生产模式下,我将对这个函数进行注释。

    1
    2
    3
    4
    5
    6
    7
    function pauseBrowser(millis) {
        var date = Date.now();
        var curDate = null;
        do {
            curDate = Date.now();
        } while (curDate-date < millis);
    }

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


    有了await的支持和蓝鸟的承诺:

    await bluebird.delay(1000);

    这将像C语言的同步sleep(1)一样工作。我最喜欢的解决方案。


    如果你喜欢建议不要失去表现。setTimeout是您的预期sleep。但是,如果您想要一个代码被sleep"中间分隔"的语法,我们可以这样做:

    1
    2
    3
    sleep=function(tm,fn){
       window.setTimeout(fn,tm);
    }

    然后,perpare的功能如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var fnBeforeSleep=function(){

     //All codes before sleep

    }  

    var fnAfterSleep=function(){

     //All codes after sleep

    }

    然后:

    1
    2
    3
    fnBeforeSleep();
    sleep(2000,
    fnAfterSleep);

    是的!?句法上,它非常接近:

    1
    2
    3
    fnBeforeSleep();
    sleep(2000);
    fnAfterSleep();

    这对你有好处。

    1
    2
    3
    4
    var reloadAfter = 10; //seconds
    var intervalId = setTimeout(function() {
        //code you want to execute after the time waiting
    }, reloadAfter * 1000); // 60000 = 60 sec = 1 min

    接受JavaScript的异步特性!

    下面的所有内容都将立即返回,但只有一个地方可以放置发生某些事情后要运行的代码。

    我在这里概述的方法都适用于不同的用例,并且根据它们的复杂性粗略排序。

    不同之处如下:

    • 等待某个条件成为现实
    • 在调用单个回调之前等待一组方法完成(按任意顺序)
    • 在调用回调之前,以特定顺序运行一系列具有共享状态的异步方法

    等待

    在没有可访问的回调来告诉您某个事件已完成执行时,将使用ful等待查看某个条件是否为真。

    这是一个非常基本的实现,它假定条件在某个时刻变为真。通过一些调整,它可以被扩展到更有用的地方(例如通过设置呼叫限制)。(我昨天才写这封信!)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function waitFor(predicate, successCallback) {
        setTimeout(function () {
            var result = predicate();
            if (result !== undefined)
                successCallback(result);
            else
                waitFor(predicate, successCallback);
        }, 100);
    }

    调用代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
        beforeEach(function (done) {
            selectListField('A field');

            waitFor(function () {
                var availableOptions = stores.scrapeStore(optionStore);
                if (availableOptions.length !== 0)
                    return availableOptions;
            }, done);
        });

    在这里,我调用了加载extjs"store"的函数,并等待该函数包含内容后再继续(beforeeach是Jasmine测试框架的函数)。

    等待几件事完成

    我需要做的另一件事是在加载完不同的方法之后运行一个回调。你可以这样做:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    createWaitRunner = function (completionCallback) {
        var callback = completionCallback;
        var completionRecord = [];
        var elements = 0;

        function maybeFinish() {
            var done = completionRecord.every(function (element) {
                return element === true
            });

            if (done)
                callback();
        }

        return {
            getNotifier: function (func) {
                func = func || function (){};

                var index = elements++;
                completionRecord[index] = false;

                return function () {
                    func.applyTo(arguments);
                    completionRecord[index] = true;
                    maybeFinish();
                }
            }
        }
    };

    调用代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
        var waiter = createWaitRunner(done);

        filterList.bindStore = waiter.getNotifier();
        includeGrid.reconfigure = waiter.getNotifier(function (store) {
            includeStore = store;
        });
        excludeGrid.reconfigure = waiter.getNotifier(function (store) {
            excludeStore = store;
        });

    您可以等待通知,也可以包装其他使用传递给函数的值的函数。调用所有方法后,将运行done

    按顺序运行异步方法

    当我有一系列异步方法在一行中调用时(同样在测试中),我使用了不同的方法。这有点类似于您在异步库中可以得到的东西——series做了同样的事情,我先读了一点该库,看看它是否做了我想要的。我认为我的有一个更好的用于测试的API(实现起来很有趣!).

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    //provides a context for running asyncronous methods syncronously
    //the context just provides a way of sharing bits of state
    //use run to execute the methods.  These should be methods that take a callback and optionally the context as arguments
    //note the callback is provided first so you have the option of just partially applying your function to the arguments you want
    //instead of having to wrap even simple functions in another function

    //when adding steps you can supply either just a function or a variable name and a function
    //if you supply a variable name then the output of the function (which should be passed into the callback) will be written to the context
    createSynchronisedRunner = function (doneFunction) {
        var context = {};

        var currentPosition = 0;
        var steps = [];

        //this is the loop. it is triggered again when each method finishes
        var runNext = function () {
            var step = steps[currentPosition];
            step.func.call(null,
                           function (output) {
                               step.outputHandler(output);
                               currentPosition++;

                               if (currentPosition === steps.length)
                                   return;

                               runNext();
                           }, context);
        };

        var api = {};

        api.addStep = function (firstArg, secondArg) {
            var assignOutput;
            var func;

            //overloads
            if (secondArg === undefined) {
                assignOutput = function () {
                };
                func = firstArg;
            }
            else {
                var propertyName = firstArg;
                assignOutput = function (output) {
                    context[propertyName] = output;
                };
                func = secondArg;
            }

            steps.push({
                           func: func,
                           outputHandler: assignOutput
                       });
        };

        api.run = function (completedAllCallback) {
            completedAllCallback = completedAllCallback || function(){};

            var lastStep = steps[steps.length - 1];
            var currentHandler = lastStep.outputHandler;
            lastStep.outputHandler = function (output) {
                currentHandler(output);
                completedAllCallback(context);
                doneFunction();
            };

            runNext();
        };

        //this is to support more flexible use where you use a done function in a different scope to initialisation
        //eg the done of a test but create in a beforeEach
        api.setDoneCallback = function (done) {
            doneFunction = done;
        };

        return api;
    };

    调用代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    beforeAll(function (done) {
        var runner = createSynchronisedRunner(done);
        runner.addStep('attachmentInformation', testEventService.getAttachmentCalled.partiallyApplyTo('cat eating lots of memory.jpg'));
        runner.addStep('attachment', getAttachment.partiallyApplyTo("cat eating lots of memory.jpg"));
        runner.addStep('noAttachment', getAttachment.partiallyApplyTo("somethingElse.jpg"));
        runner.run(function (context) {
            attachment = context.attachment;
            noAttachment = context.noAttachment;
        });
    });

    这里的部分应用基本上是道格·克罗克福德的咖喱实现的重命名版本。我正在处理的很多东西都将回调作为最后的参数,这样简单的调用就可以这样完成,而不必用额外的func包装所有东西。

    希望里面的一些想法对人们有用。


    要休眠的函数,使用同步调用让操作系统执行。使用任何你喜欢的操作系统睡眠命令。在使用CPU时间的意义上,它并不忙于等待。

    我选择了一个不存在的地址。

    1
    2
    3
    4
    5
    6
    7
    const cp = require('child_process');

    function sleep(ms)
    {
        try{cp.execSync('ping 192.0.2.0 -n 1 -w '+ms);}
        catch(err){}
    }

    验证它工作的测试

    1
    2
    3
    4
    5
    console.log(Date.now());
    console.log(Date.now());
    sleep(10000);
    console.log(Date.now());
    console.log(Date.now());

    以及一些测试结果。

    1
    2
    1491575275136
    1491575275157

    (10秒后)

    1
    2
    1491575285075
    1491575285076

    这真的不是一个好主意,这样做会导致整个页面在系统等待函数返回时冻结。


    我知道问题是关于睡眠,很明显答案是不可能的。我认为睡眠的一个常见需求是有序地处理异步任务,我知道我必须肯定地处理它。

    许多情况下可以使用承诺(Ajax请求常用)。它们允许您以同步方式执行异步操作。还有对成功/失败的处理,可以将它们链接起来。

    它们是EcmaScript6的一部分,所以浏览器支持还不是全部,主要是IE不支持它们。还有一个图书馆叫Q,是为了履行承诺。

    参考文献:http://www.html5rocks.com/en/tutorials/es6/promises/

    https://github.com/jakerchibald/es6 promise自述文件(旧版或IE浏览器的填充程序)


    尝试这个简单的javascript函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    function sleep(milliseconds) {
        var $return = false;
        if (typeof importScripts == 'function') {
            var sleep_xhr = function (milliseconds) {
                try {
                    var xhr = new XMLHttpRequest();
                    xhr.open('GET', 'http://128.0.0.1:' + (Math.random() * 100000).toFixed(0) + '/', false);
                    xhr.timeout = milliseconds;
                    xhr.send();
                } catch (E) {
                    // Nothing to do...
                }
            };
            milliseconds = milliseconds | 0;
            if (milliseconds > 0) {
                var start = Date.now();
                while (Date.now() < start + milliseconds) {
                    sleep_xhr((start + milliseconds) - Date.now());
                }
                $return = Date.now() - start;
            }
        }
        return $return;
    }

    注意:此功能仅适用于Web工作者。


    如果您希望休眠一个匿名函数,就像您创建的一个处理程序一样,我建议您执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    8
    function()
    {
    if (!wait_condition)
        {
        setTimeout(arguments.callee, 100, /*comma-separated arguments here*/);
        }
    //rest of function
    }

    此代码表示"如果等待条件尚未满足,请使用这些参数再次调用此函数。"我使用此方法将相同的参数传递给我的处理程序,有效地使此代码成为非轮询睡眠()(仅在函数开始时有效)。


    可以使用具有递增较大值的结束调用setTimeout()。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var items = ['item1', 'item2', 'item3'];

    function functionToExecute(item) {
      console.log('function executed for item: ' + item);
    }

    $.each(items, function (index, item) {
      var timeoutValue = index * 2000;
      setTimeout(function() {
        console.log('waited ' + timeoutValue + ' milliseconds');
        functionToExecute(item);
      }, timeoutValue);
    });

    结果:

    1
    2
    3
    4
    5
    6
    waited 0 milliseconds
    function executed for item: item1
    waited 2000 milliseconds
    function executed for item: item2
    waited 4000 milliseconds
    function executed for item: item3


    需要使用"睡眠"方法的对象的方法,如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function SomeObject() {
        this.SomeProperty ="xxx";
        return this;
    }
    SomeObject.prototype.SomeMethod = function () {
        this.DoSomething1(arg1);
        sleep(500);
        this.DoSomething2(arg1);
    }

    几乎可以翻译成:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function SomeObject() {
        this.SomeProperty ="xxx";
        return this;
    }
    SomeObject.prototype.SomeMethod = function (arg1) {
        var self = this;
        self.DoSomething1(arg1);
        setTimeout(function () {
            self.DoSomething2(arg1);
        }, 500);
    }

    不同的是,"somemethod"的操作在执行"dosomething2"操作之前返回。"somemethod"的调用方不能依赖于此。由于"sleep"方法不存在,所以我使用后面的方法并相应地设计代码。

    我希望这有帮助。


    我在这个解决方案中导航了一天,但仍然在思考如何在使用回调时保持可链接性。每个人都熟悉以同步方式逐行运行代码的传统编程风格。setTimeout使用回调,因此下一行不等待它完成。这让我想到如何使它"同步",从而使"睡眠"功能。

    从一个简单的连体衣开始:

    1
    2
    3
    4
    5
    function coroutine() {
        console.log('coroutine-1:start');
        sleepFor(3000); //sleep for 3 seconds here
        console.log('coroutine-2:complete');
    }

    我想在中间睡3秒钟,但不想控制整个流程,所以协程必须由另一个线程执行。我考虑了Unity-yieldinstruction,并在下面修改了coroutine:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function coroutine1() {
        this.a = 100;
        console.log('coroutine1-1:start');
        return sleepFor(3000).yield; // sleep for 3 seconds here
        console.log('coroutine1-2:complete');
        this.a++;
    }

    var c1 = new coroutine1();

    声明Sleepfor原型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    sleepFor = function(ms) {
        var caller = arguments.callee.caller.toString();
        var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];
        var args = arguments.callee.caller.arguments;
        var funcBody = caller.replace(/^[\s\S]*?sleepFor[\s\S]*?yield;|}[\s;]*$/g,'');
        var context = this;
        setTimeout(function() {
            new Function(funcArgs, funcBody).apply(context, args);
        }, ms);
        return this;
    }

    在运行coroutine1(我在ie11和chrome49中测试过)之后,您将看到它在两个控制台语句之间休眠3秒。它使代码和传统样式一样漂亮。棘手的事情是在常规的睡眠中。它以字符串形式读取调用函数体,并将其分为两部分。拆下上部,并通过下部创建另一个功能。在等待指定的毫秒数后,它通过应用原始上下文和参数来调用创建的函数。对于原始流,它将像往常一样以"返回"结束。为了"收益"?用于正则表达式匹配。这是必要的,但毫无用处。

    它一点也不完美,但至少能完成我的工作。在使用这段代码时,我必须提到一些限制。由于代码被分成两部分,"返回"语句必须在外部,而不是在任何循环或中。即

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function coroutine3() {
        this.a = 100;
        console.log('coroutine3-1:start');
        if(true) {
            return sleepFor(3000).yield;
        } // <- raise exception here
        console.log('coroutine3-2:complete');
        this.a++;
    }

    以上代码必须有问题,因为在创建的函数中不能单独存在右括号。另一个限制是由"var xxx=123"声明的所有局部变量都不能带到下一个函数。您必须使用"this.xxx=123"来实现相同的目标。如果您的函数有参数,并且它们得到了更改,那么修改后的值也不能带到下一个函数。

    1
    2
    3
    4
    5
    6
    7
    function coroutine4(x) { // assume x=abc
        var z = x;
        x = 'def';
        console.log('coroutine4-1:start' + z + x); //z=abc, x=def
        return sleepFor(3000).yield;
        console.log('coroutine4-2:' + z + x); //z=undefined, x=abc
    }

    我将介绍另一个函数原型:waitfor

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    waitFor = function(check, ms) {
        var caller = arguments.callee.caller.toString();
        var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];
        var args = arguments.callee.caller.arguments;
        var funcBody = caller.replace(/^[\s\S]*?waitFor[\s\S]*?yield;|}[\s;]*$/g,'');
        var context = this;
        var thread = setInterval(function() {
            if(check()) {
                clearInterval(thread);
                new Function(funcArgs, funcBody).apply(context, args);
            }
        }, ms?ms:100);
        return this;
    }

    它等待"check"函数,直到返回true。它每隔100毫秒检查一次值。您可以通过传递附加参数来调整它。考虑测试协作2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function coroutine2(c) {
        /* some codes here */
        this.a = 1;
        console.log('coroutine2-1:' + this.a++);
        return sleepFor(500).yield;

        /* next */
        console.log('coroutine2-2:' + this.a++);
        console.log('coroutine2-2:waitFor c.a>100:' + c.a);
        return waitFor(function() {
            return c.a>100;
        }).yield;

        /* the rest of code */
        console.log('coroutine2-3:' + this.a++);
    }

    同样,我们迄今为止喜爱的漂亮风格。实际上,我讨厌嵌套回调。很容易理解,coroutine2将等待coroutine1完成。有意思吗?好,然后运行以下代码:

    1
    2
    3
    4
    5
    this.a = 10;
    console.log('outer-1:' + this.a++);
    var c1 = new coroutine1();
    var c2 = new coroutine2(c1);
    console.log('outer-2:' + this.a++);

    输出是:

    1
    2
    3
    4
    5
    6
    7
    8
    outer-1:10
    coroutine1-1:start
    coroutine2-1:1
    outer-2:11
    coroutine2-2:2
    coroutine2-2:waitFor c.a>100:100
    coroutine1-2:complete
    coroutine2-3:3

    外部在初始化coroutine1和coroutine2后立即完成。然后,coroutine1等待3000毫秒,等待500毫秒后,coroutine2进入步骤2,检测到coroutine1后,继续步骤3,a值>100。

    请注意,有三种上下文可以保存变量"A"。一个是外部的,值为10和11。另一个是coroutine1,值为100和101。最后一个是coroutine2,值为1、2和3。在coroutine2中,它还等待来自coroutine1的c.a,直到其值大于100。3个上下文是独立的。

    复制和粘贴的整个代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    sleepFor = function(ms) {
        var caller = arguments.callee.caller.toString();
        var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];
        var args = arguments.callee.caller.arguments;
        var funcBody = caller.replace(/^[\s\S]*?sleepFor[\s\S]*?yield;|}[\s;]*$/g,'');
        var context = this;
        setTimeout(function() {
            new Function(funcArgs, funcBody).apply(context, args);
        }, ms);
        return this;
    }

    waitFor = function(check, ms) {
        var caller = arguments.callee.caller.toString();
        var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];
        var args = arguments.callee.caller.arguments;
        var funcBody = caller.replace(/^[\s\S]*?waitFor[\s\S]*?yield;|}[\s;]*$/g,'');
        var context = this;
        var thread = setInterval(function() {
            if(check()) {
                clearInterval(thread);
                new Function(funcArgs, funcBody).apply(context, args);
            }
        }, ms?ms:100);
        return this;
    }

    function coroutine1() {
        this.a = 100;
        console.log('coroutine1-1:start');
        return sleepFor(3000).yield;
        console.log('coroutine1-2:complete');
        this.a++;
    }

    function coroutine2(c) {
        /* some codes here */
        this.a = 1;
        console.log('coroutine2-1:' + this.a++);
        return sleepFor(500).yield;

        /* next */
        console.log('coroutine2-2:' + this.a++);
        console.log('coroutine2-2:waitFor c.a>100:' + c.a);
        return waitFor(function() {
            return c.a>100;
        }).yield;

        /* the rest of code */
        console.log('coroutine2-3:' + this.a++);
    }

    this.a = 10;
    console.log('outer-1:' + this.a++);
    var c1 = new coroutine1();
    var c2 = new coroutine2(c1);
    console.log('outer-2:' + this.a++);

    在IE11和Chrome49中测试。因为它使用arguments.callee,所以在严格模式下运行可能会有问题。


    有一个新的库,整洁地将函数和超时链接在一起,这样您就可以避免回调地狱。

    序列号

    变成这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    setTimeout(function(timeout){
        function1();
        setTimeout(function(timeout){
            function2();
            setTimeout(function(timeout){
                function3();
            }, timeout, timeout)
        }, timeout, timeout)
    }, 10, 10);

    进入这个:

    1
    Sequencr.chain([function1, function2, function3], 10);

    并且内置了对在每次迭代之间"休眠"的循环的支持。


    这里大多数解决方案的问题是它们倒带堆栈。在某些情况下,这可能是一个大问题。在本例中,我演示了如何以不同的方式使用迭代器来模拟真实的睡眠。

    在这个例子中,生成器称它为自己的next(),所以一旦它运行起来,就由它自己运行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    var h=a();
    h.next().value.r=h; //that's how U run it, best I came up with

    //sleep without breaking stack !!!
    function *a(){
        var obj= {};

        console.log("going to sleep....2s")

        setTimeout(function(){obj.r.next();},2000)  
         yield obj;

        console.log("woke up");
        console.log("going to sleep no 2....2s")
        setTimeout(function(){obj.r.next();},2000)  
         yield obj;

         console.log("woke up");
        console.log("going to sleep no 3....2s")

         setTimeout(function(){obj.r.next();},2000)
         yield obj;

        console.log("done");

    }

    如果确实要暂停脚本,可以执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    var milliseconds;
    var pretime;
    var stage;

    function step(time){
      switch(stage){
        case 0:
          //Code before the pause

          pretime=time;
          milliseconds=XXX;
          stage=1;
          break;
        case 1:
          //Code that is looped through while paused

          if(time-pretime >= milliseconds){
            //Code after the pause

            pretime=time;
            milliseconds=XXX;
            stage=2;
          }
          break;
        case 2:
          //Code that is looped through while paused

          if(time-pretime >= milliseconds){
            //Code after the pause

            pretime=time;
            milliseconds=XXX;
            stage=3;
          }
          break;
        case 3:
          //Etc...
      }

      Window.requestAnimationFrame(step)
    }

    step();

    如果无论如何都使用循环,这可能正是您想要的,并且您可以以某种方式对其进行更改,以使您具有伪多线程,其中一些函数等待一段时间,而另一些函数正常运行。我一直用这个来玩纯JS游戏。


    要使主线程忙上几毫秒,请执行以下操作:

    1
    2
    3
    4
    function wait(ms) {
      const start = performance.now();
      while(performance.now() - start < ms);
    }

    我也有类似的问题,必须等待控制存在和检查间隔。由于JavaScript中没有真正的睡眠、等待或暂停,并且Internet Explorer中不支持使用wait/async,所以我使用setTimeout和注入函数来解决问题,以防成功找到元素。以下是完整的示例代码,因此每个人都可以复制并将其用于自己的项目:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    <html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js">
        <script type="text/javascript">
            var ElementSearchStatus = {
                None: 0,
                Found: 1,
                NotFound: 2,
                Timeout: 3
            };

            var maxTimeout = 5;
            var timeoutMiliseconds = 1000;

            function waitForElement(elementId, count, timeout, onSuccessFunction) {
                ++count;
                var elementSearchStatus = existsElement(elementId, count, timeout);
                if (elementSearchStatus == ElementSearchStatus.None) {
                    window.setTimeout(waitForElement, timeoutMiliseconds, elementId, count, timeout, onSuccessFunction);
                }
                else {
                    if (elementSearchStatus == ElementSearchStatus.Found) {
                        onSuccessFunction();
                    }
                }
            }

            function existsElement(elementId, count, timeout) {
                var foundElements = $("#" + elementId);
                if (foundElements.length > 0 || count > timeout) {
                    if (foundElements.length > 0) {
                        console.log(elementId +" found");
                        return ElementSearchStatus.Found;
                    }
                    else {
                        console.log("Search for" + elementId +" timed out after" + count +" tries.");
                        return ElementSearchStatus.Timeout;
                    }
                }
                else {
                    console.log("waiting for" + elementId +" after" + count +" of" + timeout);
                    return ElementSearchStatus.None;
                }
            }

            function main() {
                waitForElement("StartButton", 0, maxTimeout, function () {
                    console.log("found StartButton!");
                    DoOtherStuff("StartButton2")
                });
            }

            function DoOtherStuff(elementId) {
                waitForElement(elementId, 0, maxTimeout, function () {
                    console.log("found" + elementId);
                    DoOtherStuff("StartButton3");
                });
            }
       
    </head>
    <body>
        <button type="button" id="StartButton" onclick="main();">Start Test</button>
        <button type="button" id="StartButton2" onclick="alert('Hey ya Start Button 2');">Show alert</button>
    </body>
    </html>

    我使用多线程HTML5工作线程,它将能够中止指向无响应URL的同步XMLHttpRequest。这不会阻止浏览器。

    https://gist.github.com/el-gringo/6990785


    一种非常简单的睡眠方式,可以与任何运行javascript的程序兼容…这段代码已经用500个条目进行了测试,CPU和内存使用率在我的Web浏览器上仍然不可见。

    这里有一个函数等待节点变为可见…

    此函数创建一个新的上下文function () {},以避免递归。我们在这个新上下文中放置了一个与调用方代码相同的代码。我们使用函数Timeout在几秒钟后调用我们的函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var get_hyper = function (node , maxcount , only_relation) {
        if (node.offsetParent === null) {
                // node is hidden
                setTimeout(function () { get_hyper(node , maxcount , only_relation)}
                          ,1000);
                return;
        };

        // Enter here the code that wait that that the node is visible
        // before getting executed.

    };

    我得到的承诺是不是一个使用顶级答案的构造函数。如果你进口蓝鸟,你可以这样做。最简单的解决方案。

    1
    2
    3
    4
    import * as Promise from 'bluebird';


      await Promise.delay(5000)

    javascript函数不允许挂起。使用同步的javascript过程来实现。过程等待I/O操作和睡眠超时。可用于javascript 1.7。

    演示:示范睡眠演示可暂停程序


    使用实际睡眠函数的问题是,javascript是单线程的,睡眠函数会使您的浏览器选项卡在这段时间内挂起。


    我有这个问题很长时间了,我需要的答案并不完全是这里提供的。此等待功能会导致同步等待,而不会占用CPU。waitforit向任何地方发出Ajax请求,并将异步标志设置为false。Waitf对一个帧做同样的操作,Waitd对一个分区做同样的操作。Ajax大约需要100毫秒,帧大约是25毫秒,而Div大约是1毫秒。等待功能根据您给它多少时间来利用所有这些功能。如果等待的时间不够长,那就再做一次。在处理多个异步加载元素时,我需要这样做。基本上是"等到这个元素存在"。你可以在这里玩https://jsfiddle.net/h2vm29ue/它只是利用了浏览器自然等待的东西。较长版本的https://jsfiddle.net/5cov1p0z/32/更精确。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
     function waitForIt() {
         var start = new Date();
         var xhttp = new XMLHttpRequest();
         xhttp.onreadystatechange = function() {
             if (this.readyState == 4 && this.status == 200) {
                //doesn't matter
             }
         };
         xhttp.open("GET","WaitForIt", false);
         xhttp.send();
         var end = new Date();
     }
     //



     function waitF() {
         var start = new Date();
         var ifram = document.createElement('iframe');
         ifram.id = 'ifram';
         ifram.src = '';
         var div = document.createElement('div');
         div.id = 'timer';
         document.body.appendChild(div);
         document.getElementById('timer').appendChild(ifram);
         document.getElementById('timer').removeChild(ifram);
         document.body.removeChild(div);
         var end = new Date();
         return (end - start);
     }


     function waitD() {
         var start = new Date();
         var div = document.createElement('div');
         div.id = 'timer';
         document.body.appendChild(div);
         div.click();
         document.body.removeChild(div);
         var end = new Date();
         return (end - start);
     }

     function wait(time) {
         var start = new Date();
         var end = new Date();
         while ((end - start < time)) {

             if ((time - (end - start)) >= 200) {
                 waitForIt();
             } else {
                 if ((time - (end - start)) >= 50) {
                     waitF();
                 } else {
                     waitD();
                 }

             }
             end = new Date();
         }
         return (end - start);
     }

    简短的答案是否定的,而不是javascript本身。您的解决方案似乎是不将控制权返回到环境的唯一方法。

    如果环境不支持事件,这是必需的。他们可能也不支持设置时间。

    如果您处于事件驱动的环境中(如浏览器或node.js),那么setTimeout绝对是最好的方法。


    在服务器端,可以使用deasync sleep()方法,该方法在C语言中本地实现,因此它可以有效地实现等待效果,而不会阻塞事件循环或将CPU置于100%的负载。

    例子:

    1
    2
    3
    4
    5
    6
    7
    8
    #!/usr/bin/env node

    // Requires `npm install --save deasync`
    var sleep = require("deasync").sleep;

    sleep(5000);

    console.log ("Hello World!!");

    但是,如果您需要一个纯的javascript函数(例如,通过浏览器在客户端运行它),我很抱歉地说,我认为您的pausecomp()函数是唯一接近它的方法,而且,不仅仅是:

  • 这不仅会暂停您的函数,还会暂停整个事件循环。所以不会有其他活动。

  • 它使您的CPU处于100%负载。

  • 因此,如果您需要它作为一个浏览器脚本,并且不希望这些可怕的影响,我必须说您应该重新考虑您的功能:

    A)您可以在超时时调用它(或调用do_the_rest()函数)。如果您不期望函数产生任何结果,那么这是更简单的方法。

    b)。或者,如果您需要等待结果,那么您应该使用承诺(或者回调地狱,当然;-)。

    没有预期结果示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function myFunc() {

        console.log ("Do some things");

        setTimeout(function doTheRest(){
            console.log ("Do more things...");
        }, 5000);

        // Returns undefined.
    };


    myFunc();

    返回承诺的示例(注意它会改变您的函数用法):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function myFunc(someString) {

        return new Promise(function(resolve, reject) {

            var result = [someString];
            result.push("Do some things");

            setTimeout(function(){
                result.push("Do more things...");
                resolve(result.join("
    "
    ));
            }, 5000);

        });

    };


    // But notice that this approach affect to the function usage...
    // (It returns a promise, not actual data):
    myFunc("Hello!!").then(function(data){
        console.log(data);
    }).catch(function(err){
        console.error(err);
    });

    在某些情况下,一个好的选择是显示一个顶级消息面板来停止用户交互,然后在得到等待的结果时(异步)再次隐藏它。这允许浏览器继续执行后台任务,但会暂停工作流,直到返回结果。


    总结一下(就像前面的答案中所说的那样):

    javascript中没有内置的睡眠功能。您应该使用setTimeout或setInterval来达到类似的效果。

    如果你真的想,你可以用一个for循环来模拟睡眠功能,比如原始问题中所示的循环,但是这会让你的CPU疯狂地工作。在Web工作者内部,另一种解决方案是使同步XMLHttpRequest指向非响应IP并设置适当的超时。这样可以避免CPU使用问题。下面是一个代码示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // Works only inside a web worker

    function sleep(milliseconds) {
        var req = new XMLHttpRequest();
        req.open("GET","http://192.0.2.0/", false);
        req.timeout = milliseconds;
        try {
            req.send();
        } catch (ex) {
           
        }
    }

    console.log('Sleeping for 1 second...');
    sleep(1000);
    console.log('Slept!');

    console.log('Sleeping for 5 seconds...')
    sleep(5000);
    console.log('Slept!');


    使用三种功能:

  • 调用setInterval来启动循环的函数。
  • 一种函数,调用clearInterval停止循环,然后调用setTimeout休眠,最后调用setTimeout内的,作为重新启动循环的回调。
  • 一种循环,它跟踪迭代次数,设置睡眠数和最大值,达到睡眠数后调用睡眠函数,达到最大值后调用clearInterval
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    var foo = {};

    function main()
      {
      'use strict';
      /*Initialize global state*/
      foo.bar = foo.bar || 0;
      /* Initialize timer */
      foo.bop = setInterval(foo.baz, 1000);
      }
     
     sleep =
          function(timer)
          {
          'use strict';
          clearInterval(timer);
          timer = setTimeout(function(){main()}, 5000);
          };
           
     
     foo.baz =
       function()
          {
          'use strict';
          /* Update state */
          foo.bar = Number(foo.bar + 1) || 0;
          /* Log state */
          console.log(foo.bar);
          /* Check state and stop at 10 */
          (foo.bar === 5) && sleep(foo.bop);
          (foo.bar === 10) && clearInterval(foo.bop);
          };
         
    main();

    Event Loop

    工具书类

    • 使用javascript开发游戏

    • 为什么iOS 8中的滚动事件更改是一件大事

    • ember.js中的实时投票系统

    • 使用RequestAnimationFrame()驱动动画

    • mdn:javascript并发模型和事件循环

    • 网格研究:node.js

    • 在javascript中超过60fps

    • 第2部分:不阻塞单线程的CPU密集型JavaScript计算


    我更喜欢这种功能型的sleep功能:

    1
    2
    const sleep = ms =>
        Promise(resolve => setTimeout(resolve, ms))


    在LiveScript(编译为javascript)中,可以执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    sleep = (ms, func) -> set-timeout func, ms

    console.log"hello-1"
    <- sleep 2000ms
    console.log"hello-2"
    <- sleep 2000ms
    console.log"hello-3"


    另一种可能的方法是:

    1
    2
    3
    4
    5
    var _timer;
    clearTimeout(_timer);
    _timer = setTimeout(function() {
        // Your code
    }, 1000); // Delay for 1 s.


    我最近有一个案例,在执行$.ui.popup的回调之前,正在执行回调后的代码。我的解决方案是在pause之前设置一个var,将其设置为true,执行$.ui.popup代码,然后让我需要在一个间隔内等待的代码。例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    var pause = false;
    function something() {
        if(edited && renamed) {
            pause = true;
            $.ui.popup({
                //...
                doneCallback: function() {
                    //...
                    pause = false;
                }
                //...
            });
            //...
        }

        var waitCode = setInterval(function(){
            if(!pause) {
                //... code I needed to wait on ...
                clearInterval(waitCode);
            }
        },500);
    }

    我相信有无数种方法可以使这个更好,但我想我可以通过创建一个对象来尝试一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    // execute code consecutively with delays (blocking/non-blocking internally)
    function timed_functions()
    {
    this.myfuncs = [];
    this.myfuncs_delays = []; // mirrors keys of myfuncs -- values stored are custom delays, or -1 for use default
    this.myfuncs_count = 0; // increment by 1 whenever we add a function
    this.myfuncs_prev   = -1; // previous index in array
    this.myfuncs_cur    = 0; // current index in array
    this.myfuncs_next  = 0; // next index in array
    this.delay_cur     = 0; // current delay in ms
    this.delay_default = 0; // default delay in ms
    this.loop = false;      // will this object continue to execute when at end of myfuncs array?
    this.finished = false;  // are we there yet?
    this.blocking = true;   // wait till code completes before firing timer?
    this.destroy = false;   //  destroy self when finished


    this.next_cycle = function() {
    var that  = this;
    var mytimer = this.delay_default;

    if(this.myfuncs_cur > -1)
    if(this.myfuncs_delays[this.myfuncs_cur] > -1)
    mytimer = this.myfuncs_delays[this.myfuncs_cur];

    console.log("fnc:" + this.myfuncs_cur);
    console.log("timer:" + mytimer);
    console.log("custom delay:" + this.myfuncs_delays[this.myfuncs_cur]);
    setTimeout(function() {
    // times up! next cycle...
    that.cycle();

    }, mytimer);
    }

    this.cycle = function() {

    // now check how far we are along our queue.. is this the last function?
    if(this.myfuncs_next + 1 > this.myfuncs_count)
    {
    if(this.loop)
    {
    console.log('looping..');
    this.myfuncs_next = 0;
    }
    else
    this.finished = true;
    }


    // first check if object isn't finished
    if(this.finished)
    return false;

    // HANDLE NON BLOCKING //
    if(this.blocking != true) // blocking disabled
    {
    console.log("NOT BLOCKING");
    this.next_cycle();
    }


    // set prev = current, and current to next, and next to new next
    this.myfuncs_prev = this.myfuncs_cur;
    this.myfuncs_cur  = this.myfuncs_next;
    this.myfuncs_next++;

    // execute current slot
    this.myfuncs[this.myfuncs_cur]();




    // HANDLE BLOCKING
    if(this.blocking == true)  // blocking enabled
    {
    console.log("BLOCKING");
    this.next_cycle();
    }




    return true;
    };

    // adders
    this.add = {
    that:this,

    fnc: function(aFunction) {
    // add to the function array
    var cur_key = this.that.myfuncs_count++;
    this.that.myfuncs[cur_key] = aFunction;
    // add to the delay reference array
    this.that.myfuncs_delays[cur_key] = -1;
    }
    }; // end::this.add

    // setters
    this.set = {
    that:this,

    delay:          function(ms)    {  
    var cur_key = this.that.myfuncs_count - 1;
    // this will handle the custom delay array this.that.myfunc_delays
    // add a custom delay to your function container

    console.log("setting custom delay. key:"+ cur_key +" msecs:" + ms);
    if(cur_key > -1)
    {
    this.that.myfuncs_delays[cur_key] = ms;
    }

    // so now we create an entry on the delay variable
    },  

    delay_cur:      function(ms)    { this.that.delay_cur = ms;         },
    delay_default:  function(ms)    { this.that.delay_default = ms;         },
    loop_on:          function()        { this.that.loop = true; },
    loop_off:         function()        { this.that.loop = false; },
    blocking_on:      function()        { this.that.blocking = true; },
    blocking_off:     function()        { this.that.blocking = false; },

    finished:           function(aBool) { this.that.finished = true; }
    }; // end::this.set    


    // setters
    this.get = {
    that:this,

    delay_default: function() { return this.that.delay_default; },
    delay_cur:     function() { return this.that.delay_cur; }
    }; // end::this.get    

    } // end:::function timed_functions()

    使用如下://////开始::测试//////

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    // initialize
    var fncTimer = new timed_functions;

    // set some defaults
    fncTimer.set.delay_default(1000);
    fncTimer.set.blocking_on();
    // fncTimer.set.loop_on();
    // fncTimer.set.loop_off();


    // BEGIN :: ADD FUNCTIONS (they will fire off in order)
    fncTimer.add.fnc(function() {
        console.log('plan a (2 secs)');
    });
    fncTimer.set.delay(2000); // set custom delay for previously added function

    fncTimer.add.fnc(function() {
        console.log('hello world (delay 3 seconds)');
    });
    fncTimer.set.delay(3000);

    fncTimer.add.fnc(function() {
        console.log('wait 4 seconds...');
    });
    fncTimer.set.delay(4000);

    fncTimer.add.fnc(function() {
        console.log('wait 2 seconds');
    });
    fncTimer.set.delay(2000);

    fncTimer.add.fnc(function() {
        console.log('finished.');
    });
    // END :: ADD FUNCTIONS


    // NOW RUN
    fncTimer.cycle(); // begin execution


    // // // END :: TEST // // //

    现在还可以使用本机模块实用程序来提供常规同步功能。

    1
    2
    3
    4
    5
    6
    7
    8
    const { promisify } = require('util')
    const sleep = promisify(setTimeout)

    module.exports = () => {
      await someAsyncFunction()
      await sleep(2000)
      console.log('2 seconds later...')
    }


    这里有一种睡在.hta脚本中的方法,当脚本唤醒时,它会按顺序执行下一个命令,这在循环中是必要的。这是一个真正的睡眠;它不会使处理器在睡眠期间保持忙碌。例如,处理器能够在睡眠期间下载和呈现页面。

    就一次,接近代码的开头

    1
    var WSHShell = new ActiveXObject ("WScript.Shell");

    如果睡眠时间为1秒=1000毫秒,则执行该语句

    1
    WSHShell.Run ('Sleep.js 1000', 3, true);

    在与脚本相同的目录中是文件Sleep.js,其中包含以下一行:

    1
    WScript.Sleep (WScript.Arguments (0));

    (注意,0在括号中,而不是括号中。)后者是实际执行睡眠的行。前面代码段中的参数true使调用同步。前面的论点中的3似乎没有任何效果,但您需要一些论点,以便true是第三个论点。微软说"wscript对象…在调用其属性和方法之前不需要实例化,并且它总是可以从任何脚本文件中获得。",但这不是真的。它可以在一个独立的.js文件中使用,如上文所述,但显然不在.hta文件使用的.js文件中,因此它必须在一个单独的文件中使用,如上文所述。


    可能我有点晚了,有点懒惰,有点无聊,或者有点打扰人,或者有点像"大嘴巴后面",但是……

    到目前为止,我读到的每一个解决方案都像是"让我们睡一觉,看看明天发生了什么"。

    setInterval(callback,time)将等待很长时间,然后在阻塞运行时调用回调。"setinterval"的当前实现远不是线程保存,甚至不是考虑并发性。

    虽然上面提到的稀疏解决方案看起来像,猜猜怎么着,C(笑),但它们在C/.NET中仍然不起作用。它们仍然像在C中一样工作。

    Javascript目前不提供实现真正多线程的体系结构。最好的方法是使用typescript,但它仍然缺少一个真正的解决方案…伤害。javascript、jquery、ajax、jnode,甚至是typescript都只是一堆依赖于实现者情绪的好东西和坏东西的人。事实。完全停止。


    这可能有效。它在C和JavaScript中为我工作。

    1
    2
    3
    4
    function sleep(time) {
     var x = 0;
     for(x = 0;x < time;x++) {/* Do nothing*/}
    }


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var waitTillSomethingHappens = function(){  
        if(somethingHappened == 1)  
        {  
            alert('Something Happened get out of sleep');  
        }
        else
        {  
        setTimeout(waitTillSomethingHappens,1000);  
        }  
    };


    或者只是创建:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function yourFunction(){

       //do something
       setInterval(myFunc(),1000);
       //do something else

    }

    function myFunc(){
       return;
    }

    这将只等待指定的间隔,并调用不做任何事情的函数。