web-dev-qa-db-ja.com

JavaScript版のsleep()とは何ですか?

次のsleep関数( ここから取られた )よりもJavaScriptでpausecompを設計するより良い方法はありますか?

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

これは、 JavaScriptのスリープ - アクション間の遅延 ;の複製ではありません。私は、コードの一部が実行されるまでの遅延ではなく、関数の途中で 本当の睡眠 が欲しいのです。

1863
fmsf

2017年 - 2019年の更新

この質問が行われた2009年以来、JavaScriptは大きく進化しました。他のすべての答えは現在廃止されているか、または過度に複雑です。これが現在のベストプラクティスです。

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, showing sleep in a loop...');

  // Sleep in loop
  for (let i = 0; i < 5; i ++) {
  if (i === 3)
    await sleep(2000);
  console.log(i);
  }
}

demo();

これです。 await sleep(<duration>)

ご了承ください、

  1. awaitは、asyncキーワードが接頭辞として付いた関数内、または環境によってはスクリプトの 最上位レベル でのみ実行できます(Chrome DevToolsコンソール、Runkitなど)。
  2. awaitは現在のasync関数のみを一時停止します

2つの新しいJavaScript機能により、この「スリープ」機能を作成することができました。

互換性

何らかの奇妙な理由で7よりも古いNodeを使用している( EOLに到達した )場合、または古いブラウザをターゲットにしている場合でも、async/awaitBabeltransform-async-to-generator プラグインを使用して、 transpile JavaScript +新しい機能を単純な古いJavaScriptに変換する)ツール。

1668
Dan Dascalescu

(2016年の 更新された回答を参照してください

アクションを実行し、待ってから別のアクションを実行するのは、まったく合理的だと思います。あなたがマルチスレッド言語で書くことに慣れているなら、あなたはおそらくあなたのスレッドが目覚めるまで一定時間実行を譲るという考えを持っています。

ここでの問題は、JavaScriptがシングルスレッドのイベントベースのモデルであるということです。特定のケースでは、エンジン全体を数秒間待機させるのがいいかもしれませんが、一般的には悪い習慣です。私が自分のものを書いている間あなたの関数を利用したいと思ったとしたら?私があなたのメソッドを呼び出すと、私のメソッドはすべてフリーズします。 JavaScriptが何らかの形で関数の実行コンテキストを保存し、それをどこかに保存してから元に戻して後で続行すると、スリープが発生する可能性がありますが、基本的にはスレッド化です。

だから、あなたは他の人が提案したことにほとんど固執しています - あなたはあなたのコードを複数の関数に分割する必要があるでしょう。

あなたの質問は少し間違った選択です。あなたが望む方法で眠る方法はなく、あなたが提案する解決策を追求するべきでもありません。

839
Ben Flynn

JavaScriptでは、できるだけ早く終了できるようにすべての関数を書き換えます。 DOMを変更できるように、ブラウザを元に戻します。

関数の途中で眠りたいと思う度にsetTimeout()を使うようにリファクタリングしました。

私はこれが便利だと思ったのでこの答えを編集します。

悪名高い睡眠、または遅延、任意の言語内で機能については多くの議論があります。ある特定の機能を起動するシグナルまたはコールバックが常にあるべきだと言う人もいれば、時々任意の遅延の瞬間が有用であると主張する人もいるでしょう。私は、それぞれが独自に、そして一つの規則がこの業界で何かを決定することは決してできないと言います。

Sleep関数を書くのは簡単で、JavaScript Promiseを使うとさらに使いやすくなります。

// sleep time expects milliseconds
function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

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

debug/dev の場合のみ、誰かに役立つ場合はこれを投稿します

興味深いことに、Firebug(およびおそらく他のjsコンソール)では、enterを押しても何も起こらず、指定された睡眠時間が経過した後にのみ(...)

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

使用例

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

私は他のポスターに同意します、忙しい睡眠は単なる悪い考えです。

ただし、setTimeoutは実行を遅らせることはなく、タイムアウトが期限切れになった直後ではなくタイムアウトが設定された直後に関数の次の行を実行するため、スリープと同じタスクは実行されません。

それをする方法はあなたの機能を部品の前後に分解することです。

function doStuff()
{
  //do some things
  setTimeout(continueExecution, 10000) //wait ten seconds before continuing
}

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

あなたの関数名がそれぞれの部分が何をしているかをまだ正確に記述していることを確認してください(funcPart1とfuncPart2ではなく、GatherInputThenWaitとCheckInput)。

編集

この方法では、タイムアウトした後に決定したコード行を実行しないという目的を達成しながら、キューに入っているもの以外は実行するようにクライアントPCに制御を戻します。

さらに編集

コメントで指摘されているように、これはループ内では絶対に機能しません。あなたはそれをループ内で動作させるためにいくつかの空想的な(醜い)ハッキングをすることができましたが、一般的にそれは悲惨なスパゲッティコードのためになるでしょう。

171
DevinB

$ DEITYが大好きな人のために、ビジー状態のスリープ機能は使わないでください。 setTimeoutsetIntervalはあなたが必要とするすべてをします。

118
chaos

これはちょっと古い質問ですが、(私のように)RhinoでJavascriptを使用しているのであれば、使用することができます。

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.
   */
}
112
mjaggard

あなたがjQueryを使っているなら、誰かが実際にsetTimeoutのラッパーに過ぎない "遅延"プラグインを作成しました:

// 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;
};

そうすれば、期待通りに一連の関数呼び出しでそれを使うことができます。

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');
66
Alan Plum

私はスリープソリューションも検索し(製品コードではなく、開発/テストのみ)、この記事を見つけました。

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

...そしてクライアントサイドのソリューションとのもう一つのリンクがあります: http://www.devcheater.com/ /

また、alert()を呼び出しているときは、alertが表示されている間もコードが一時停止されます - alertを表示しないが同じ効果を得る方法を見つける必要があります。 :)

43
a_w

どうぞ。コードが言うように、悪い開発者にならないで、これをウェブサイトで使ってください。開発ユーティリティ機能です。

// 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) {}
}
30
Ian Maddox

これは同期XMLHttpRequestを使った簡単な解決策です:

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の内容:

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

今それを呼び出します。sleep(5);

25
pguardiario

最初:

実行したい機能を次のように定義します。

function alertWorld(){
  alert("Hello World");
}

それからsetTimeoutメソッドで実行をスケジュールします。

setTimeout(alertWorld,1000)

二つのことに注意してください

  • 2番目の引数はミリ秒単位の時間です
  • 最初の引数として、括弧なしで関数の名前(参照)だけを渡す必要があります
18
Pablo Fernandez

私は個人的にはシンプルが好きです。

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

その後:

sleep(2); // Sleeps for 2 seconds

私はP5jsでスクリプトを作成しながら偽のロード時間を作成するためにそれをずっと使っています

18
Akelian

物事をほとんどの人が望むもののように見せるためのより良い解決策は無名関数を使うことです:

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

これはおそらくあなたが単にあなたが望むことをする何かになるでしょう最も近いです。

あなたが複数の睡眠を必要とするならば、これは急いで醜くなるかもしれません、そしてあなたは実際にあなたのデザインを再考する必要があるかもしれません。

15
Mainguy

他の非同期タスクとのコードの一貫性のために、setTimeOutをPromiseにカプセル化します。 Fiddle のデモ

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

そのように使われる:

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

Promiseを使ったことがあれば、構文を覚えるのは簡単です。

10
Elo

ここでの答えの大部分は誤って導かれているか、あるいは少なくとも時代遅れです。 javascriptがシングルスレッドでなければならない理由はありません。実際、そうではありません。 RhinoやNode.jsのような他のjavascriptランタイムがマルチスレッドをサポートするようになる前に、今日ではすべての主流ブラウザがワーカーをサポートしています。

'Javascript is single threaded'は有効な答えではありません。たとえば、ワーカー内でスリープ関数を実行しても、uiスレッドで実行されているコードは一切ブロックされません。

ジェネレータと歩留まりをサポートする新しいランタイムでは、シングルスレッド環境のスリープ機能に同様の機能をもたらすことができます。

// 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で動作するはずです。

9
Gabriel Ratener

ブラウザの場合は、setTimeoutとsetIntervalが適していると思います。

しかし、サーバーサイドコードの場合は、ブロッキング機能が必要になる可能性があります(たとえば、スレッド同期を効果的に行うことができます)。

Node.jsとmeteorを使用している場合は、setTimeoutをファイバで使用する際の制限に遭遇したかもしれません。これがサーバーサイドスリープのコードです。

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

9
Homer6
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}
8
Shemeer M Ali

私はjavascriptのsleep/waitでかなりの数のウェブページを検索/グーグルしました...そしてJavaScriptを "RUN、DELAY、RUN"にしたいのであれば答えはありません...もの)、RUN "または" RUN、RUN +遅延RUN "....

だから私はいくつかのハンバーガーを食べて、考えました:::これはうまくいく解決策です...しかし、あなたはあなたの実行中のコードを切り刻む必要があります... :::はい、私は知っていますまだ...

// ................................ // example1:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//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);

</script>
</body>
</html>

// .............................. // example2:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//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
</script>
</body>
</html>

// ................. example3:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//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
</script>
</body>
</html>

// .............. example4:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//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...
</script>
</body>
</html>
8
user207408

多くの答えは(直接)質問に答えません、そしてまたこれもしません...

これが私の2セント(または機能)です。

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ミリ秒ごと、...")と読みやすくなります。

6
1j01

SetTimeout()を使うよりもsleep()関数を使いたいというシナリオの1つは、ユーザークリックに応答する関数があり、それが最終的に新しいポップアップウィンドウを開くことになり、短時間の処理が必要な場合です。ポップアップが表示される前に完了します。開いているウィンドウを閉じて移動すると、通常はブラウザによってブロックされます。

6
acuth

同期実行を扱わなければならない場合、私はスリープ機能の目的を理解することができます。 setInterval関数とsetTimeout関数は、実行シーケンスをメインプログラムに返す並列実行スレッドを作成します。これは、与えられた結果を待つ必要がある場合は無効です。もちろん、イベントやハンドラを使うこともできますが、意図したものではない場合もあります。

6
naazgull

Javaのsleepメソッドを使って実行できます。私はFFとIEでそれをテストしました、そしてそれはコンピュータをロックしたり、リソースをかみ砕いたり、あるいは無限のサーバーヒットを引き起こすことはありません。私にとってはきれいな解決策のようです。

まず、Javaをページにロードしてそのメソッドを使用可能にする必要があります。それをするために、私はこれをしました:

<html>
<head>

<script type="text/javascript">

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

</script>

<body onLoad="load()">

<embed id="app" code="Java.applet.Applet" type="application/x-Java-applet" MAYSCRIPT="true" width="0" height="0" />

それから、あなたがあなたのJSで痛みのない一時停止が欲しいときにしなければならないのはすべてです:

Java.lang.Thread.sleep(xxx)

Xxxはミリ秒単位の時間です。私の場合(正当化の理由で)、これは非常に小さな会社でのバックエンドの注文処理の一部であり、私はサーバーからロードしなければならない請求書を印刷する必要がありました。私は請求書を(Webページとして)iFrameにロードしてからiFrameを印刷することによってそれを行いました。もちろん、印刷する前にページが完全に読み込まれるまで待たなければならなかったので、JSは一時停止しなければなりませんでした。私は、(iFrame内の)請求書ページで、親ページの隠しフォームフィールドをonLoadイベントで変更することでこれを実現しました。請求書を印刷するための親ページのコードは、次のようになっています(無関係な部分は、わかりやすくするために切り取っています)。

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.

6
Rachael

私の2ビットを追加します。私はテスト目的のために忙しく待つ必要がありました。コードを分割するのは面倒なので、やりたくありませんでした。

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

私はこれを行うことに少しのマイナス面も見ません、そしてそれは私のためにトリックをしました。

6
caiocpricci2

あなたはJavaScriptのように眠ることはできません。スリープまたはwhileループを実行すると、ループが完了するまでユーザーのブラウザがハングします。

参照したリンクで指定されているように、タイマーを使用してください。

5
Andrew Dunkman

ループによって実行されている一連の呼び出しをスペースで区切るという特定のケースでは、prototypeを使用して以下のコードのようなものを使用できます。プロトタイプがなくても、遅延関数をsetTimeoutに置き換えることができます。

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)
}
5
beauburrier

Node.jsを使っているのなら、 fiber - nodeへのネイティブC拡張、ちょっとマルチスレッドのシミュレーションを見てください。

それはあなたがファイバーの実行をブロックしている方法で本当のsleepをすることを可能にします、しかしそれはメインスレッドと他のファイバーの中でノンブロッキングです。

これが自分たちのreadmeからの新鮮な例です:

// 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');

- そして結果は:

$ 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)
5
tomekwi

2009年からの古い質問です。2015年には、ES6とも呼ばれるECMAscript 2015で定義されたジェネレータを使用して、新しい解決策が可能になりました。 6月に承認されましたが、以前はFirefoxとChromeに実装されていました。これで、ブラウザをフリーズさせることなく、スリープ機能を非ビジー、ノンブロッキング、ループ内のネストやサブ機能にすることができます。純粋なJavaScriptだけが必要で、ライブラリやフレームワークは必要ありません。

以下のプログラムはどのようにsleep()runSleepyTask()を作ることができるかを示しています。 sleep()関数はyieldステートメントにすぎません。 sleep()を呼び出す代わりにyieldステートメントを直接書くほうが実際には簡単なのでとても簡単ですが、sleep-Wordはありません:-) yieldはnext()内のwakeup()メソッドに時間値を返して待ちます。実際の「眠り」は古きwakeup()を使ってsetTimeout()で行われます。コールバック時にnext()メソッドはyieldステートメントを続行させます。yieldの「魔法」はすべてのローカル変数とそれを取り巻く全体のコールスタックがまだ無傷であることです。

Sleep()またはyieldを使用する関数はジェネレータとして定義されなければなりません。キーワードfunction*にアスタリスクを追加することで簡単に行えます。ジェネレータを実行するのは少し面倒です。キーワードnewを指定して呼び出すと、ジェネレータはnext()メソッドを持つオブジェクトを返しますが、ジェネレータ本体は実行されません(キーワードnewはオプションであり、違いはありません)。 next()メソッドは、yieldに遭遇するまでジェネレータ本体の実行をトリガします。ラッパー関数runSleepyTask()はピンポンを起動します。next()yieldを待ち、yieldnext()を待ちます。

ジェネレータを呼び出すもう1つの方法は、キーワードyield*を使用することです。ここでは単純な関数呼び出しのように機能しますが、next()に戻す機能も含まれています。

これはすべてdrawTree()の例で証明されています。回転する3Dシーンに木の葉を描きます。木は、異なる方向にある上部に3つの部分を持つトランクとして描かれます。その後、短いスリープの後にdrawTree()を再帰的に呼び出すことによって、各部分は別のより小さなツリーとして描画されます。非常に小さな木が葉として描かれています。

それぞれの葉はrunSleepyTask()で始まる別々のタスクでそれぞれの生活をしています。それはgrowLeaf()で生まれ、成長し、座り、消え、そして死んでいく。速度はsleep()で制御されます。これは、マルチタスクがいかに簡単にできるかを示しています。

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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>

3Dのものはsetup3D()の中に隠されていて、console.log()よりもつまらないものにするためだけに含まれています。ところで天使はラジアンで測られます。

FirefoxとChromeで動作することがテスト済みです。 Internet ExploreおよびiOS(iPad)には実装されていません。自分で実行してみてください。

私が見つけた答えの別のパスの後、そのGabriel Ratenerは1年前に同様の答えをしました: https://stackoverflow.com/a/24401317/5032384

5
Ole Middelboe

この link から取得したコードはcompをフリーズしません。しかし、それはffでのみ動作します。

/**
 * 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);
    }
}
4
CoR

ノード7.6 以降、utilsモジュールのpromisify関数をsetTimeoutと組み合わせることができます。

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

一般的な使い方

async function main() {
    console.time("Slept for")
    await sleep(3000)
    console.timeEnd("Slept for")
}

main()

質問の使い方

async function asyncGenerator() {
    while (goOn) {
      var fileList = await listFiles(nextPageToken);
      await sleep(3000)
      var parents = await requestParents(fileList);
    }
  }
4
Harry

あなたがこのような睡眠機能を正しければ

var sleep = function(period, decision, callback){
    var interval = setInterval(function(){
        if (decision()) {
            interval = clearInterval(interval);
            callback();
        }
    }, period);
}

そして、あなたは複数回呼び出す非同期関数を持っています

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

そして、あなたはこのようにあなたのプロジェクトを設定します:

var ready = false;

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

それからこれをすることができます:

xhr1();
sleep(100, function(){ return done; }, xhr2);
sleep(100, function(){ return done; }, xhr3);
sleep(100, function(){ return done; }, function(){
    // do more
});

このような無限のコールバックインデントの代わりに:

xhr(url1, function(){
    xhr2(url2, function(){
        xhr3(url3, function(){
            // do more
        });
    });
});
4
BishopZ

まず第一に - setTimeoutとsetIntervalは何です - JavaScriptのコールバックっぽい性質のために、 を使うべきです。 sleep()を使いたいのであれば、それはあなたのコードの制御フローやアーキテクチャの誤りです。

私は私がまだ睡眠の2つの実施を手伝うことができると思うと言っていた。

  1. 私の頭の上から同期ランニングを偽造する:

    //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 
     }
    })();
    

    【再生を自動にすることも可能です】

    //usage
    
    _.go(function(){
    
    //your code
    console.log('first');
    
    });
    
    
    _.sleep(5000);
    
    _.go(function(){
    
    //your code
    console.log('next');
    
    });
    
    //this triggers the simulation
    _.playback();
    
  2. 実同期ラン

ある日私はそれについて多くの考えを与えました、そして私がジャバスクリプトの中で本当の睡眠のために持っていた唯一の考えは技術的です。

スリープ関数は、タイムアウトをスリープ値に設定した synchronic AJAX呼び出しである必要があります。それが本当のsleep()を持つためのすべてで唯一の方法です

4
naugtur

本当に何かをテストするためだけにsleep()が必要な場合。しかし、デバッグ中はほとんどの場合ブラウザがクラッシュすることに注意してください - おそらくそれがあなたがとにかくそれを必要とする理由です。プロダクションモードでは、この機能をコメントアウトします。

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

あなたがメモリ、処理能力、バッテリーそしておそらくあなたのデバイスの寿命を無駄にしたくない限り、ループの中でnew Date()を使わないでください。

3
Rodrigo

OSにそれをさせる同期呼び出しを使用して、スリープする機能。好きなOSのスリープコマンドを使ってください。 CPU時間を消費するという意味で待つのは忙しくありません。

存在しないアドレスに対してpingを実行しました。

const cp = require('child_process');

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

それが機能することを確認するためのテスト

console.log(Date.now());
console.log(Date.now());
sleep(10000);
console.log(Date.now());
console.log(Date.now());

そしていくつかのテスト結果。

1491575275136
1491575275157

(そして10秒後)

1491575285075
1491575285076
2
user3070485

これは本当に良い考えではありません、システムがあなたの関数が戻るのを待っている間、このような何かをすることはページ全体をフリーズさせるでしょう。

2
Scimon

あなたはパフォーマンスを損なわないように助言が好きなら。 setTimeoutはあなたの予想されるsleepです。ただし、コードがsleepで「中央に分割」されている構文が欲しい場合は、

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

それから、次のように機能します。

var fnBeforeSleep=function(){

 //All codes before sleep

}  

var fnAfterSleep=function(){

 //All codes after sleep

}  

その後:

fnBeforeSleep();
sleep(2000,
fnAfterSleep);

うん!構文的には、次のようになります。

fnBeforeSleep();
sleep(2000); 
fnAfterSleep();
2
Abdennour TOUMI

awaitサポートと bluebirdの約束で

await bluebird.delay(1000);

これはc言語の同期sleep(1)のように動作します。私のお気に入りの解決策.

2
Guang-De Lin
  await new Promise(resolve => setTimeout(resolve, 2000));

呼び出し関数が非同期であることを確認してください

検証済みで正常に動作している

2

Javascriptの非同期性を受け入れましょう。

以下はすべてすぐに戻りますが、何かが起こった後に実行したいコードを置くための場所が1つあります。

ここで概説した方法はすべてさまざまなユースケースのためのものであり、それらの複雑さの観点からおおまかに並べられています。

異なることは次のとおりです。

  • ある条件が真になるのを待っている
  • 単一のコールバックを呼び出す前に、一連のメソッドが(任意の順序で)終了するのを待つ
  • コールバックを呼び出す前に、共有状態を持つ一連の非同期メソッドを特定の順序で実行する

待機

何らかの条件が満たされているかどうかを確認するのを待つのは、何かが実行を終了したことを知らせるためのアクセス可能なコールバックがない場合に役立ちます。

これはかなり基本的な実装で、ある時点で条件が真になることを前提としています。いくつかの調整により、さらに便利になるように拡張することができます(たとえば、通話制限を設定することによって)。 (私は昨日これを書いただけです!)

function waitFor(predicate, successCallback) {
    setTimeout(function () {
        var result = predicate();
        if (result !== undefined)
            successCallback(result);
        else
            waitFor(predicate, successCallback);
    }, 100);
}

呼び出しコード:

    beforeEach(function (done) {
        selectListField('A field');

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

ここで私はextjs 'store'をロードする何かを呼んでいて、続行する前にそのストアに何かが含まれるのを待っています(beforeEachはjasmineのテストフレームワークです)。

いくつかのことが完了するのを待ちます

私がしなければならなかったもう一つのことは、異なるメソッドのロードが終了した後に単一のコールバックを実行することでした。あなたはこのようにすることができます:

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();
            }
        }
    }
};

呼び出しコード:

    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が実行されます。

非同期メソッドを順番に実行する

連続して呼び出すための一連の非同期メソッドがある場合は(別のテストで)、別の方法を使用しました。これはあなたが得ることができるものにいくらか似ています Asyncライブラリ - シリーズはほぼ同じことをします、そして私が最初に私が望んだことをしたかどうか見るためにそのライブラリについて少し読みました。私は、テストを扱うためのより良いAPIを持っていると思います(+実装するのは楽しかったです!).

//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;
};

呼び出しコード:

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;
    });
});

PartiallyApplyToは、基本的にDoug CrockfordによるCurryの実装の名前を変更したものです。私が取り組んでいるものの多くは最後の引数としてコールバックを取りますので、余分な関数ですべてをラップする必要はなく、このように単純な呼び出しを行うことができます。

うまくいけば、そこにあるアイデアのいくつかは人々に役立つかもしれません。

2
JonnyRaa

私は質問が睡眠に関するものであることを知っています、そして明らかに答えはそれが不可能であるということです。私は睡眠のための一般的な欲求が順番に非同期のタスクを扱うことであると思います、私は私が確かにそれに対処しなければならなかったことを知っています。

多くの場合、約束を使用することができるかもしれません(AJAXは一般的な使用を要求します)。それらはあなたに同期的な方法で非同期的なことをさせます。成功/失敗の処理もあり、それらは連鎖することができます。

これらはECMAScript 6の一部なので、ブラウザのサポートはまだすべてではなく、主にIEはそれらをサポートしていません。約束をするためのQというライブラリもあります。

参照先: http://www.html5rocks.com/en/tutorials/es6/promises/

https://github.com/jakearchibald/es6-promise#readme (古いシム、またはIEブラウザ)

2
Xeridea

これでうまくいくでしょう。

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

この単純なJavaScript関数を試してください。

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ワーカー でのみ機能します。

2
Chandra Nakka

私は1日解決策をたどりますが、それでもコールバックを使用して連鎖性を維持する方法を考えています。誰もが同期した方法でコードを1行ずつ実行する伝統的なプログラミングスタイルに精通しています。 SetTimeoutはコールバックを使用するので、次の行はそれが完了するのを待ちません。これにより、「スリープ」機能を作成するために、どのようにしてそれを「同期」させるかを考えることができます。

単純なコルーチンから始めます。

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

途中で3秒間スリープしたいのですが、フロー全体を支配したくないので、コルーチンは別のスレッドで実行する必要があります。 Unity YieldInstruction を考えて、コルーチンを以下のように修正します。

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プロトタイプを宣言します。

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でテストしました)、2つのコンソールステートメントの間に3秒間スリープします。それはコードを伝統的なスタイルと同じくらいきれいに保ちます。注意が必要なのはsleepForルーチンです。呼び出し元の関数本体を文字列として読み取り、それを2つの部分に分割します。上部を取り除き、下部に別の機能を作成します。指定したミリ秒数待機した後、元のコンテキストと引数を適用して、作成した関数を呼び出します。元のフローの場合は、通常どおり「return」で終了します。 「収量」は?これは正規表現のマッチングに使用されます。それは必要ですが、まったく役に立ちません。

100%完璧というわけではありませんが、少なくとも私の仕事は達成できます。このコードを使用する際のいくつかの制限について言及しなければなりません。コードが2つの部分に分割されているので、 "return"ステートメントは、ループや{}ではなく、外側にある必要があります。すなわち.

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++;
}

上記のコードは、閉じ括弧が作成された関数内に個別に存在できないため、問題があるはずです。もう1つの制限は、 "var xxx = 123"で宣言されているすべてのローカル変数が次の関数に持ち込めないことです。同じことを実現するには、 "this.xxx = 123"を使用する必要があります。関数に引数があり、それらが変更された場合、変更された値は次の関数にも引き継がれません。

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

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;
}

Trueが返されるまで「check」関数を待ちます。 100msごとに値をチェックします。追加の引数を渡すことで調整できます。テストcoroutine2を考えます。

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の完了を待つことは容易に理解できます。面白い?それでは、次のコードを実行します。

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

出力は以下のとおりです。

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ミリ秒待機します。コルーチン2は500ms待った後、ステップ2に入ります。その後、coroutine1.aの値が100を超えると、手順3を続行します。

変数 "a"を保持するための3つのコンテキストがあることに注意してください。もう1つはcoroutine1、値は100、101です。最後の値はcoroutine2、値は1、2、3です。 coroutine1から、その値が100を超えるまで。3つのコンテキストは独立しています。

コピー&ペーストのためのコード全体:

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
cscan

あなたが 本当に スクリプトを一時停止したい場合は、これを実行できます。

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
Caty Lawren

クロージャー呼び出しsetTimeout()を使用して、徐々に大きな値を指定することができます。

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);
});

結果:

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
tponthieux

ハンドラーとして作成したもののような無名関数をスリープさせたい場合は、以下のことをお勧めします。

function()
{
if (!wait_condition)
    {
    setTimeout(arguments.callee, 100, /*comma-separated arguments here*/);
    }
//rest of function
}

このコードでは、「待機条件がまだ満たされていない場合は、これらの引数を使用してこの関数をもう一度呼び出します」と述べています。私はこのメソッドを使って私のハンドラに同じ引数を渡し、事実上このコードを非ポーリングのsleep()にしています(これはあなたの関数の開始時にのみ有効です)。

1
Aaron

ここでのほとんどの解決策の問題はそれらがスタックを巻き戻すことです。これは場合によっては大きな問題になる可能性があります。この例では、 実際の睡眠 をシミュレートするためのイテレータの使い方を示します。

この例では、ジェネレータはそれ自身のnext()を呼び出しています。

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
O_Z

あなたがコールバック地獄を避けることができるようにきちんとタイムアウトと一緒に機能を連鎖する新しいライブラリがあります。

Sequencr.js

これを回します:

setTimeout(function(timeout){
    function1();
    setTimeout(function(timeout){
        function2();
        setTimeout(function(timeout){
            function3();
        }, timeout, timeout)
    }, timeout, timeout)
}, 10, 10);

これに:

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

そして、各繰り返しの間に「スリープ」するループのサポートが組み込まれています。

1
JSideris

次のような「スリープ」メソッドを使用する必要があるオブジェクトのメソッド。

function SomeObject() {
    this.SomeProperty = "xxx";
    return this;
}
SomeObject.prototype.SomeMethod = function () {
    this.DoSomething1(arg1);
    sleep(500);
    this.DoSomething2(arg1);
}

ほとんどに翻訳することができます:

function SomeObject() {
    this.SomeProperty = "xxx";
    return this;
}
SomeObject.prototype.SomeMethod = function (arg1) {
    var self = this;
    self.DoSomething1(arg1);
    setTimeout(function () {
        self.DoSomething2(arg1);
    }, 500);
}

違いは、操作「DoSomething2」が実行される前に「SomeMethod」の操作が戻ることです。 "SomeMethod"の呼び出し元はこれに依存できません。 "Sleep"メソッドは存在しないので、私は後者のメソッドを使い、それに応じてコードを設計します。

これが助けになれば幸いです。

1

要約すると(以前の回答で述べたように):

JavaScriptには組み込みのスリープ機能はありません。同様の効果を得るには、 setTimeout または setInterval を使用する必要があります。

本当にやりたければ、最初の質問で示したようなforループを使ってスリープ機能をシミュレートすることもできますが、それはあなたのCPUをクレイジーに動作させるでしょう。 Webワーカーの内部では、代替の解決策として、応答しないIPに対して同期的なXMLHttpRequestを作成し、適切なタイムアウトを設定することが考えられます。これにより、CPU使用率の問題を回避できます。これがコード例です。

// 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!');
0
Miscreant

サーバー側では、Cにネイティブに実装されている deasyncsleep()メソッドを使用できるので、event-loopをブロックすることなくwait効果を効果的に実装できますまたはCPUを100%の負荷にします。

例:

#!/usr/bin/env node

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

sleep(5000);

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

しかし、pure javascript関数が必要な場合(たとえば、ブラウザでクライアント側で実行する場合)、私はあなたのpausecomp()関数がそれに近づく唯一の方法だと思うのは残念です。それ以上:

  1. それはあなたの機能だけでなく、イベントループ全体を一時停止します。他のイベントには参加しません。

  2. それは100%の負荷であなたのCPUを置きます。

それで、あなたがブラウザスクリプトのためにそれを必要とし、それらのひどい効果を望まないならば、私はあなたがあなたの機能をある方法で再考するべきであると言わなければなりません:

a)。タイムアウト時にそれを呼び出すことができます(またはdo_the_rest()関数を呼び出す)。あなたがあなたの関数から少しの結果も期待していないならばもっと簡単な方法。

b)。あるいは、もしあなたが結果を待つ必要があるならば、それからあなたは約束を使うことに移るべきです(あるいはもちろんコールバック地獄;-))。

予想される結果はありません。

function myFunc() {

    console.log ("Do some things");

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

    // Returns undefined.
};


myFunc();

約束を返す例(関数の使い方が変わることに注意してください):

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("\n"));
        }, 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);
});
0
bitifet

私は同様の問題を抱えていました。コントロールの存在を待ち、間隔を置いてチェックしなければならなかったためです。 JavaScriptには本当の睡眠、待機または一時停止がなく、await/asyncの使用はInternet Explorerでは適切にサポートされていないので、setTimeOutを使用して要素を見つけることができた場合は関数を挿入するソリューションを作りました。ここに完全なサンプルコードがありますので、誰でも自分のプロジェクトのためにそれを複製して使うことができます:

<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <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");
            });
        }
    </script>
</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>
0
Franz Kiermaier

2019 Atomics.waitを使用して更新

ノード9.3以降で動作するはずです。

Node.jsにはかなり正確なタイマーが必要でしたが、それには最適です。しかし、ブラウザでのサポートは非​​常に限られているようです。

let ms = 10000;
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);

数10秒のタイマーベンチマークを実行しました。

SetTimeoutを使用すると、最大7000マイクロ秒のエラーが発生します。 (7ms)

Atomicsでは、私のエラーは600マイクロ秒以下にとどまるようです。 (0.6ms)

0
Kapytanhook

私は長い間この質問をしてきました、そして私が必要とした答えはまさにここで提供されたものではありませんでした。この待機機能は、CPUを拘束しない同期待機を引き起こします。 waitForItはどこかにajaxリクエストを行い、asyncフラグをfalseに設定します。 waitFはフレームと同じことをし、waitDはdivと同じことをします。 Ajaxは約100ミリ秒かかり、フレームは約25、そしてdivは約1です。wait関数は、どれだけの時間を与えるかによって、これらすべてを利用します。それが十分に長く待たなかったならば、それをまたやりなさい。複数の非同期ロード要素を扱うときにこれが必要です。基本的には「この要素が存在するまで待つ」ということです。あなたはここでそれをプレイすることができます https://jsfiddle.net/h2vm29ue/ それはブラウザが自然に待つものを利用するだけです。より長いバージョン https://jsfiddle.net/5cov1p0z/32/ はより正確です。

 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);
 }
0
God Ѻ

私はプロミスがトップアンサーを使っているコンストラクタではないことを手に入れました。あなたがbluebirdをインポートするなら、あなたはこれをすることができます。最も簡単な解決策のイモ。

import * as Promise from 'bluebird';


  await Promise.delay(5000)
0
ByteMe

Javascriptを実行するものと互換性があります。このコードは、500のエントリのようなものでテストされています、CPUおよびメモリ使用量は私のウェブブラウザでまだ見えない。

これはノードが見えるようになるまで待つ1つの関数です...

この関数は再帰を避けるために新しいコンテキストfunction () {}を作成します。この新しいコンテキスト内に、呼び出し側のコードと同じことをするコードを配置しました。数秒後に関数Timeoutを使用して関数を呼び出します。

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.

};
0
MUY Belgium

簡単な答えは _ no _ であり、それ自体はjavascriptにはありません。あなたの解決策は、制御を環境に戻さない唯一の方法のようです。

環境がイベントをサポートしていない場合、これは必要です。おそらくそれらはsettimeoutもサポートしないでしょう。

ブラウザやnode.jsなどのイベント駆動型環境にいる場合は、settimeoutは間違いなく最善の方法です。

0
Gerard ONeill

実際のスリープ機能を使用する場合の問題は、JavaScriptがシングルスレッドであり、スリープ機能によってブラウザのタブがその間ハングアップすることです。

0
mukund

Javascript関数は中断を許しません。同期Javascriptの手順で実装されています。プロシージャは入出力操作とスリープタイムアウトを待ちます。 javascript 1.7で利用可能です。

デモ: デモ睡眠デモ中断可能手続き

0
Paul Stettler

メインスレッドを数ミリ秒間ビジー状態にするには

function wait(ms) {
  const start = performance.now();
  while(performance.now() - start < ms);
}
0
pomber

場合によっては、最善のメッセージパネルを表示してユーザーの操作を停止し、(非同期的に)待っている結果が表示されたら再び非表示にすることもできます。これにより、ブラウザはバックグラウンドタスクを実行できますが、結果が返されるまでワークフローは一時停止します。

0

応答のないURLを指す同期XMLHttpRequestを中止できるようになるマルチスレッドHTML5ワーカーを使用します。これはブラウザをブロックしません。

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

0
user2882556