web-dev-qa-db-ja.com

Javascriptのsleep()

奇妙な理由でJavascriptの実行を一定時間ブロックしたい場合、どうすればよいですか。 JSにはsleep()はありません。それは悪いので、plsはwhile()ループを行うとは言いません。 window.showModalDialogを実行し、ユーザーがダイアログに気付かないように、setTimeoutを非常に短い時間でモーダルダイアログにwindow.closeを配置できます。これは短時間の睡眠のようなもので、必要に応じて何度も呼び出すことができます。他に方法はありますか?

詳述すると、私のユースケースはHTML5 SQLデータベースが非同期APIを提供しているというものですが、ストアが決して大きくならないsamllwebappに使用したいと思います。したがって、小さなストアでのクエリはクライアント側で実行されるため、非同期APIは必要ありません。そこで、開発者がより簡単に使用できるように、syncapiを使用してORMを作成したいと思います。この非同期をブリッジしてapiを同期するには、sleepのようなものが必要です。

14
nomind

window.setTimeout または window.setInterval はほとんどあなたの唯一の友達です。

setTimeoutを使用して、別のタイムアウトを設定する関数を再帰的に呼び出す方法の例は次のとおりです。

function go() {
    if (go.count < 4) {
        // logs 1, 2, 3 to firebug console at 1 second intervals
        console.log(go.count++);
        window.setTimeout(go, 1000);
    }
}
go.count = 1;

go();

終了する前にタイムアウトをクリアする必要がある場合は、 window.clearTimeout で使用するtimeoutIDをキャプチャすることを選択できます。

window.setTimeoutwindow.setInterval 他のスクリプトの実行もブロックしないことに注意してください-現在の装いでJavaScriptを使用するとこれが可能になるとは思いません。 showModalDialogを使用したり、恐れている限り近いグローバルなblockingブール値を使用したりするなど、UIブロッキングを模倣するようにコーディングできる方法がいくつかあります。

14
Russ Cam

@Russ Camは正しいです、setTimeoutはあなたが探しているものです。しかし、あなたが質問でそれを述べた方法は、それがどのように使われるかについていくらかの混乱があるかもしれないと私に思わせます。

存在するブロックの実行をブロックするのではなく、一定の間隔の後に入力関数を呼び出します。実例として:

function illustration() {
  // start out doing some setup code
  alert("This part will run first");

  // set up some code to be executed later, in 5 seconds (5000 milliseconds):
  setTimeout(function () {
    alert("This code will run last, after a 5 second delay")
  }, 5000);

  // This code will run after the timeout is set, but before its supplied function runs:
  alert("This will be the second of 3 alert messages to display");
}

この関数を実行すると、2番目と3番目の間に遅延がある3つのアラートメッセージが表示されます。

  1. 「この部分が最初に実行されます」
  2. 「これは、表示される3つのアラートメッセージの2番目になります」
  3. 「このコードは、5秒の遅延後に最後に実行されます」
9
pkaeding

明確にするために:問題は、スクリプトの実行を一定時間完全に停止することであり、setTimeoutまたはsetIntervalのタスクとなるコードの実行を遅らせることではありません。

Sleep()のクリーンな実装は不可能であり、JavaScriptでは望ましくありません。

setTimoutとsetIntervalは、ここの一部の人々が考えているように、スクリプトの実行を停止しません。実行する関数を登録するだけで延期されます。スクリプトの残りの部分は、タイムアウト/間隔が待機している間も実行を継続します。

JavaScriptは非同期であるため、コードの実行を「ブロック」する唯一の方法は、非常に醜く、指定された時間実行されるwhileループは絶対にお勧めしません。 JavaScript自体は単一のスレッドで実行されるため(ここではWebWorkers APIについては説明していません...)。これにより、ループが終了するまでJSコードの実行が停止します。しかし、それは本当に悪いスタイルです...

Sleep()のようなものがないとプログラムが機能しない場合は、アプローチを再考する必要があります。

6
selfawaresoup

Window.showModalDialogを実行し、非常に短い時間のsetTimeoutでモーダルダイアログにwindow.closeを配置できます。

これは独創的ですが、開いている間は、モーダルダイアログ内のすべてのものとのユーザーインタラクションのみが可能です。ブラウザの残りの部分は、残忍なwhile (new Date().getTime()<t1);ループを呼び出したかのように確実にハングしたままになります。

モーダルダイアログはCPUサイクルにやさしく、待機時間が長くなった場合にscript-execution-timeウォッチドッグをトリガーすることを回避しますが、気が散る点滅するダイアログボックスの煩わしさと、ユニバーサルブラウザのサポート、およびモーダルダイアログを嫌うすべての人の問題!

これは短時間の睡眠のようなもので、必要に応じて何度も呼び出すことができます。他に方法はありますか?

あなたは実際に睡眠によって何を達成しようとしていますか?イベントループに戻るか、モーダルダイアログを起動しないと、画面上の更新やユーザーインタラクションが得られないため、インラインスリープがどのように機能するかわかりません。あなたは確かにこの方法でアニメーションを行うことはできません。

Firefoxでは、Pythonスタイルの generators を取得します。これにより、yieldを使用して手続き型の対話プロセスを記述し、必要に応じてブラウザーに制御を戻すことができます。これにより、変数の記憶状態として条件付きおよびループ構造を書き直す必要がないため、コードの単純さが向上します。ただし、Mozillaブラウザのみがサポートしているため、当面の間、実際に使用することはできません。

ETA:

開発者がより簡単に使用できるように、syncapiを使用してORMを作成したいと思います。この非同期をブリッジしてapiを同期するには、sleepのようなものが必要です。

申し訳ありませんが、一般的なケースでは実行できません。基本的なJavaScriptには、同期コードと非同期コードをブリッジできるスレッド、コルーチン、またはその他のプリミティブがありません。

Web SQL Databaseの仕様は、ブラウザーのコールバックとして結果処理関数(executeSql()に渡される)を呼び出すブラウザーに依存しています。ブラウザのコールバックは、実行の同期スレッド内ではなく、制御がブラウザに戻ったときにのみ発生します。

理論的には、modalDialogを開き、非同期Web SQLデータベース呼び出しinsidemodalDialogのウィンドウを実行し、modalDialogに呼び出し元ウィンドウのスクリプトの同期コードになります。ただし、現在、openDatabaseopenModalDialogの両方をサポートするブラウザはありません!

3
bobince

この答えは少し面倒かもしれませんが、それで裸です:-)。

Javascriptは通常、マルチスレッドであり、javascriptが複数のスレッドを占有する可能性があるブラウザ内で実行されるため、シングルスレッドプログラムの場合のような「グローバルスリープ」の概念はありません。

合理的な方法で操作を一時停止する場合は、次のことを検討してください。

次のことをしたいとしましょう

function foo(s) {
    var j = 1; var k = 1;
    sleep(s); // This would be Nice right?  
    window.alert("Sum is : " + (j+k));
}

実際には次のようになります。

function foo(s) {
     var j = 1 ; var k = 1;
     setTimeout(s, function() { 
            window.alert("Sum is : " + (j+k));
     });
}

もちろん、問題は、手続き的な意味で、次のようなものが必要になる可能性があることです。

function foo() {
   do stuff;
   pause();
   do more stuff;
   return;
}

function bar() {
      foo(10);
      window.alert("I want this to happen only after foo()");
}

問題は、上記のように、setTimeoutを使用して実際にそれを行うことができないことです

ただし、次のようなことができます。

 function foo(s, afterwards, afterparms) {
     var j = 1 ; var k = 1;
     setTimeout(s, function() { 
            window.alert("Sum is : " + (j+k));
            afterparms.parm1 = afterparms.parm1.toUpperCase();
            afterwards(afterparms);
     });
 }

 function bar() {
      foo(10, function() {
          window.alert("This will happen after window.alert");
      }, { parm1: 'hello', parm2: 'world' } );
 }

上記は関数に情報を渡すための唯一の方法であることに注意してください。関数の呼び出し規約や変数引数などを調べると、本当にすばらしいことができます

手続き的に考えると、これはプログラムするのが面倒です。ただし、javascriptに関して覚えておくべきことが2つあります。これは手続き型言語ではありません。NORはオブジェクト指向言語です。Javascriptは高度なイベント管理モデルを備えた関数型言語です。したがって、これらの用語で考える必要があります。

典型的なjavascriptマシンはGUI(Webブラウザー)であり、設計上、何かを処理しようとしているときに完全にブロックすることを望まないため、これも理にかなっています。ページが何かをしているときにブラウザが完全にロックされると想像してみてください。それを行うプログラマーを絞め殺したいと思うでしょう。

Javascriptコードは「ファイア・アンド・フォーゲット」の性質のものである必要があり、続行する前にイベントが発生するのを待つ必要がある場合は、javascriptイベントモデルを確認する必要があります。

これは些細なことをしたいときに不便なプログラミングですが、最初は競合状態に陥る可能性のある方法で一時停止を使用して待機している可能性があり、その「効果」を回避するためのより適切な方法がありますあなたは達成しようとしています。

特定のケースを投稿すると、そのような状況にどのように対処できるかについて、さらに多くの情報が提供される可能性があります。

乾杯、

3
Elf King

この質問は少し古いことは知っていますが、ページへの読み込みに時間がかかるスクリプトをシミュレートする必要があるという同様の問題がありました。応答を送信する前に5秒待機するサーバー側エンドポイントを作成し、これを指すスクリプトタグをDOMに追加することで、問題を解決することになりました。

確かに、サーバー側の実装が必要ですが、特定の時点でページを停止することができます。他の人が以前に言ったように、これはあなたのスクリプトだけでなくブラウザ全体をブロックします。

1
Russ Bradberry