3106

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

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

これはJavaScriptのSleepの複製ではありません-アクション間の遅延; コードの一部が実行されるまでの遅延ではなく、関数の途中で実際にスリープする必要があります。

4

88 に答える 88

4089

2017 — 2021 更新

この質問がされた 2009 年以降、JavaScript は大幅に進化しました。他のすべての回答は現在、時代遅れであるか、過度に複雑です。現在のベスト プラクティスは次のとおりです。

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

またはワンライナーとして:

await new Promise(r => setTimeout(r, 2000));

または

const sleep = ms => new Promise(r => setTimeout(r, ms));

次のように使用します。

await sleep(<duration>);

デモ:

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

async function demo() {
    for (let i = 0; i < 5; i++) {
        console.log(`Waiting ${i} seconds...`);
        await sleep(i * 1000);
    }
    console.log('Done');
}

demo();

ご了承ください、

  1. awaitキーワードのプレフィックスが付いた関数でのみ、またはますます多くの環境でasyncスクリプトの最上位でのみ実行できます。
  2. await現在のasync機能を一時停止するだけです。これは、スクリプトの残りの部分の実行をブロックしないことを意味します。これは、ほとんどの場合に必要なことです。ブロッキング コンストラクトが必要な場合は、を使用してこの回答を参照してください。ただし、ほとんどのブラウザでは、ブラウザのメイン スレッドで許可されないことに注意してください。Atomics.wait

2 つの新しい JavaScript 機能 (2017 年現在) が、この「スリープ」関数の作成に役立ちました。

  • Promise は ES2015 (別名 ES6) のネイティブ機能です。sleep 関数の定義でもアロー関数を使用します。
  • このasync/await機能により、コードは promise が解決 (解決または拒否) されるのを明示的に待機できます。

互換性

何らかの理由で 7 ( 2017 年にサポート終了async) よりも古い Node を使用している場合、または古いブラウザーをターゲットにしている場合でも、 Babel ( JavaScript + 新機能を単純な古い JavaScript にトランスパイルするツール) をawait介して引き続き使用できます。 、プラグインで。transform-async-to-generator

于 2016-10-07T09:44:56.400 に答える
860

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

アクションを実行し、待機してから別のアクションを実行することは、完全に合理的だと思います。マルチスレッド言語での記述に慣れている場合は、スレッドが起動するまでの一定時間、実行を放棄するという考えがあるでしょう。

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

したがって、他の人が提案したものにかなりこだわっています。コードを複数の関数に分割する必要があります。

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

于 2011-05-13T13:21:37.483 に答える
735

JavaScript では、できるだけ早く終了できるようにすべての関数を書き直します。ブラウザが DOM を変更できるように、ブラウザの制御を元に戻す必要があります。

関数の途中でスリープが必要になるたびに、 を使用するようにリファクタリングしましたsetTimeout()

編集

悪名高いスリープまたは遅延機能は、どの言語でもよく議論されています。特定の機能を起動するためのシグナルまたはコールバックが常に必要であると言う人もいれば、任意の瞬間の遅延が役立つ場合があると主張する人もいます。この業界では、それぞれ独自のルールや 1 つのルールで何かを決定することはできません。

sleep 関数を書くのは簡単で、JavaScript Promises を使えばさらに使いやすくなります:

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

// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});
于 2009-06-04T14:46:54.350 に答える
337

Firebug (およびおそらく他の JavaScript コンソール)では、Enter キーを押しても何も起こらず、指定されたスリープ期間が経過した後にのみ (...)

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

使用例:

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

function sleepThenAct(){
    sleepFor(2000);
    console.log("Hello, JavaScript sleep!");
}

sleepThenAct()

注:デバッグおよび開発専用

于 2013-07-30T00:31:49.537 に答える
197

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

ただし、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 に制御を戻して、待機中の他のものを実行します。

コメントで指摘されているように、これはループでは絶対に機能しません。ループ内で機能させるために派手な (醜い) ハッキングを行うこともできますが、一般的には悲惨なスパゲッティ コードになるだけです。

于 2009-06-04T14:55:29.917 に答える
150

$ DEITYを愛するために、ビジーウェイトスリープ機能を作成しないでください。 setTimeout必要なことはすべて行いsetIntervalます。

var showHide = document.getElementById('showHide');
setInterval(() => {
    showHide.style.visibility = "initial";
    setTimeout(() => {
        showHide.style.visibility = "hidden"
    }, 1000);
    ;
}, 2000);   
<div id="showHide">Hello! Goodbye!</div>

2秒間隔ごとに、1秒間テキストが非表示になります。これは、setIntervalとsetTimeoutを使用して、毎秒テキストを表示および非表示にする方法を示しています。

于 2009-06-04T14:44:03.713 に答える
113

(私のように) 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.
   */
}
于 2011-11-04T14:16:06.403 に答える
73

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');
于 2009-06-10T18:50:32.927 に答える
59

使用する:

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

呼び出し関数が非同期であることを確認してください。これは確認済みで、正常に動作しています。

于 2019-06-26T11:27:12.747 に答える
34

どうぞ。コードが示すように、悪い開発者にならず、これを Web サイトで使用してください。開発ユーティリティ関数です。

// 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) {}
}
于 2012-11-03T02:02:47.950 に答える
32

同期 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);
于 2014-11-03T23:22:20.300 に答える
26

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

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

それから:

sleep(2); // Sleeps for 2 seconds

p5.j​​sでスクリプトを作成しているときに、偽のロード時間を作成するために常に使用しています。

于 2016-11-12T19:56:33.300 に答える
26

初め:

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

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

次に、 setTimeoutメソッドを使用して実行をスケジュールします。

setTimeout(alertWorld, 1000)

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

  • 2 番目の引数はミリ秒単位の時間です
  • 最初の引数として、括弧なしで関数の名前 (参照) だけを渡す必要があります
于 2009-06-04T14:47:52.723 に答える
20

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

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

これはおそらく、あなたが望むことを単純に行う何かに到達するのに最も近いものです。

複数のスリープが必要な場合、これは急いで醜くなる可能性があり、実際にデザインを再考する必要があるかもしれないことに注意してください。

于 2011-08-08T13:05:30.897 に答える
19

Atomics.waitを使用した 2019 の更新

Node.js 9.3 以降で動作するはずです。

私は Node.js でかなり正確なタイマーを必要としていましたが、それはうまく機能します。

ただし、ブラウザでのサポートは非​​常に限られているようです。

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

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

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

Atomics を使用すると、エラーは 600 マイクロ秒 (0.6 ミリ秒) 未満にとどまるようです

2020 アップデート: まとめ

function sleep(millis){ // Need help of a server-side page
  let netMillis = Math.max(millis-5, 0); // Assuming 5 ms overhead
  let xhr = new XMLHttpRequest();
  xhr.open('GET', '/sleep.jsp?millis=' + netMillis + '&rand=' + Math.random(), false);
  try{
    xhr.send();
  }catch(e){
  }
}

function sleepAsync(millis){ // Use only in async function
  let netMillis = Math.max(millis-1, 0); // Assuming 1 ms overhead
  return new Promise((resolve) => {
    setTimeout(resolve, netMillis);
  });
}
function sleepSync(millis){ // Use only in worker thread, currently Chrome-only
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, millis);
}

function sleepTest(){
  console.time('sleep');
  sleep(1000);
  console.timeEnd('sleep');
}

async function sleepAsyncTest(){
  console.time('sleepAsync');
  await sleepAsync(1000);
  console.timeEnd('sleepAsync');
}

function sleepSyncTest(){
  let source = `${sleepSync.toString()}
    console.time('sleepSync');
    sleepSync(1000);
    console.timeEnd('sleepSync');`;
  let src = 'data:text/javascript,' + encodeURIComponent(source);
  console.log(src);
  var worker = new Worker(src);
}

サーバー側のページはsleep.jsp次のようになります。

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>
于 2019-06-01T11:01:35.867 に答える
12

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

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

次のように使用されます。

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

Promise の使用に慣れている場合は、構文を覚えるのは簡単です。

于 2015-07-09T13:59:21.790 に答える
12

ここでの回答のほとんどは、見当違いであるか、少なくとも時代遅れです。JavaScript がシングルスレッドでなければならない理由はありませんし、そうではありません。現在、主流のブラウザはすべてワーカーをサポートしています。これが実現する前は、 Rhinoや Node.jsなどの他の JavaScript ランタイムがマルチスレッドをサポートしていました。

「JavaScript はシングル スレッドです」は有効な回答ではありません。たとえば、ワーカー内でスリープ関数を実行しても、UI スレッドで実行されているコードはブロックされません。

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

// This is based on the latest ES6 drafts.
// JavaScript 1.7+ (SpiderMonkey/Firefox 2+) syntax is slightly different

// Run code you want to sleep here (omit star if using JavaScript 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(){
        // Omit .value if using JavaScript 1.7
        var nextSleep = generator.next().value;
        resume(nextSleep, generator);
    }, ms);
}

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

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

このスリープの模倣は、スレッドをブロックしないため、真のスリープ機能とは異なります。これは、JavaScript の現在のsetTimeout関数の上に単に砂糖を加えたものです。この機能タイプはTask.jsに実装されており、現在 Firefox で動作するはずです。

于 2014-06-25T06:05:59.513 に答える
10

JavaScriptのスリープ/待機に関するかなりの数のWebページを検索/グーグルで検索しました...そして、JavaScriptを「RUN、DELAY、RUN」にしたい場合、答えはありません...ほとんどの人が得たのは、「RUN、RUN(役に立たない」のいずれかでしたstuff), RUN" または "RUN, RUN + 遅れた RUN"...

私は考えました:これはうまくいく解決策です...しかし、実行中のコードを切り刻む必要があります...:はい、わかっています、これは読みやすいリファクタリングです...それでも...

例 1:

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

例 2:

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

例 3:

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

例 4:

<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>
于 2009-11-10T04:22:27.983 に答える
9
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}
于 2013-11-09T18:37:54.373 に答える
9

setTimeoutおよびよりも扱いにくい関数が必要な場合setIntervalは、引数の順序を逆にして適切な名前を付けるだけの関数でそれらをラップできます。

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ミリ秒ごと、...」)と簡単に読み取れるようになりました。

于 2015-01-04T04:41:17.707 に答える
9

同期実行に対処する必要がある場合、スリープ機能の目的を理解できます。setInterval および setTimeout 関数は、実行シーケンスをメイン プログラムに戻す並列実行スレッドを作成します。これは、特定の結果を待たなければならない場合には効果がありません。もちろん、イベントとハンドラーを使用することもできますが、場合によっては意図したものではありません。

于 2011-06-21T17:41:26.240 に答える
8

Java の sleep メソッドを使用して実行できます。Firefox と Internet Explorer でテストしたところ、コンピューターがロックされたり、リソースが消費されたり、無限のサーバー ヒットが発生したりすることはありません。それは私にはきれいな解決策のようです。

まず、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" />

次に、JavaScript コードで痛みのない一時停止が必要な場合に行う必要があるのは、次のとおりです。

java.lang.Thread.sleep(xxx)

xxx はミリ秒単位の時間です。私の場合 (正当化のため)、これは非常に小規模な会社でのバックエンドの注文処理の一部であり、サーバーからロードする必要のある請求書を印刷する必要がありました。請求書を (Web ページとして) iFrame にロードし、iFrame を印刷することでそれを行いました。

もちろん、印刷する前にページが完全に読み込まれるまで待たなければならなかったため、JavaScript コードを一時停止する必要がありました。請求書ページ (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();

したがって、ユーザーがボタンを押すと、スクリプトは請求書ページをロードして待機し、請求書ページのロードが完了したかどうかを 1/4 秒ごとに確認し、ユーザーが印刷ダイアログをポップアップしてプリンタに送信できるようにします。QED。

于 2013-01-14T01:32:07.647 に答える
7

ループによって実行されている一連の呼び出しの間隔を空けたいという特定のケースでは、プロトタイプで以下のコードのようなものを使用できます。プロトタイプがない場合は、遅延関数を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)
}
于 2010-05-27T19:45:00.927 に答える
7

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

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

于 2009-06-04T14:46:51.087 に答える
7

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

于 2010-10-18T19:45:43.023 に答える
6

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

sleep()以下のプログラムは、作成方法と作成方法を示していますrunSleepyTask()。関数はsleep()単なるyieldステートメントです。yieldを呼び出す代わりにステートメントを直接記述する方が実際には簡単なほど単純ですがsleep()、スリープ ワードはありません :-) yield はnext()内部のメソッドに時間値を返し、wakeup()待機します。実際の「眠り」はwakeup()、古き良き時代の を使用して行われsetTimeout()ます。コールバックで、next()メソッドはステートメントを続行するようにトリガーします。yieldyieldの「魔法」は、すべてのローカル変数とその周りの呼び出しスタック全体がまだ無傷であることです。

sleep() または yield を使用する関数は、ジェネレーターとして定義する必要があります。キーワードにアスタリスクを追加することで簡単に実行できますfunction*。ジェネレーターを実行するのは少しトリッキーです。キーワードで呼び出されると、newジェネレーターはメソッドを持つオブジェクトを返しますがnext()、ジェネレーターの本体は実行されません (キーワードnewはオプションであり、違いはありません)。このnext()メソッドは、yield. ラッパー関数runSleepyTask()はピンポンを開始します。 a を待ち、 next()ayieldyield待ちますnext()

ジェネレーターを呼び出すもう 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 Explorer および iOS (iPad) には実装されていません。自分で実行してみてください。

私が見つけた回答をもう一度パスした後、Gabriel Ratener が 1 年前sleep() の JavaScript バージョンは何ですか?に対して同様の回答をしました。.

于 2015-10-10T00:43:07.910 に答える
6

sleep メソッドでは、任意の then-able オブジェクトを返すことができます。そして、必ずしも新しい約束ではありません。

例:

const sleep = (t) =>  ({ then: (r) => setTimeout(r, t) })

const someMethod = async () => {

    console.log("hi");
    await sleep(5000)
    console.log("bye");
}

someMethod()

于 2020-09-25T19:06:28.553 に答える
4

First of all - setTimeout and setInterval is what should be used, because of JavaScript's callback-ish nature. If you want to use sleep() it's the control flow or the architecture of your code that is incorrect.

Having said that I suppose I still can help with two implementation of a sleep.

1. Faking synchronous run off the top of my head:

// A module to do that //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
  }
})();

[making playback automatic should also be possible]

// Usage

_.go(function(){

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

});

_.sleep(5000);

_.go(function(){

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

});

// This triggers the simulation
_.playback();

2. Real synchronous run

I gave it a lot of thought one day and the only idea I had for a true sleep in JavaScript is technical.

A sleep function would have to be a synchronous Ajax call with a timeout set to the sleep value. That's all and the only way to have a real sleep().

于 2011-08-09T08:53:48.490 に答える
4

このリンクから取得したコードは、コンピューターをフリーズしません。ただし、Firefox でのみ機能します。

/**
 * 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 extension for Firefox.
     * Since Firefox 3, 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 finishes.
      */
    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);
    }
}
于 2011-12-03T10:40:21.270 に答える
4

このようなスリープ関数を書くと

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

複数回呼び出す非同期関数があり、

var xhr = function(url, callback){
    // Make an Ajax request
    // Call a callback when the request fulfils
}

そして、次のようにプロジェクトを設定します。

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
        });
    });
});
于 2013-07-29T21:20:11.637 に答える
3

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

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

メモリ、処理能力、バッテリー、そしておそらくデバイスの寿命を浪費したくない場合を除いて、ループ内で new Date() を使用しないでください。

于 2015-01-09T22:17:48.023 に答える
3

テスト目的でビジーウェイトが必要でした。コードを分割すると大変な作業になるので、コードを分割したくなかったので、単純なfor で分割しました。

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

これを行うことにマイナス面は見られず、それは私にとってはうまくいきました。

于 2012-12-20T11:57:30.730 に答える
2

段階的に大きな値を指定して、クロージャ コール 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
于 2014-04-28T17:30:58.543 に答える
2

これでうまくいきます。

var reloadAfter = 10; //seconds
var intervalId = setTimeout(function() {
    //code you want to execute after the time waiting
}, reloadAfter * 1000); // 60000 = 60 sec = 1 min
于 2016-12-22T09:51:47.883 に答える
2

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

多くの場合、Promise を使用できる可能性があります ( Ajaxは一般的な使用を要求します)。それらを使用すると、非同期的なことを同期的に行うことができます。成功/失敗のハンドリングもあり、連鎖することができます。

これらは ECMAScript 6 の一部であるため、ブラウザーのサポートはまだ完全ではありません。主に、Internet Explorer はそれらをサポートしていません。promise を行うための Q というライブラリもあります。

参考文献:

于 2015-01-22T18:19:22.363 に答える
2

JavaScript の非同期性を受け入れましょう!

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

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

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

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

待って

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

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

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

ここでは、 Ext JSの「ストア」をロードする何かを呼び出し、続行する前にストアに何かが含まれるまで待機しています ( beforeEachJasmineテスト フレームワークのものです)。

いくつかの処理が完了するまで待ちます

また、さまざまなメソッドのロードが終了した後に、単一のコールバックを実行する必要がありました。次のようにできます。

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

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

一連の非同期メソッドを連続して呼び出す場合は、別のアプローチを使用しました (これもテストで)。これは、非同期ライブラリで取得できるものと多少似ています。シリーズはほぼ同じことを行い、最初にそのライブラリを少し読んで、それが私が望んでいたことをしたかどうかを確認しました。ただし、私のものには、テストを操作するためのより優れた API があると思います (そして、実装するのは楽しかったです!)。

// Provides a context for running asynchronous methods synchronously
// 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
    // For example, 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は、基本的にDouglas Crockfordによる Curry の実装の名前が変更されたバージョンです。私が扱っているものの多くは、最後の引数としてコールバックを取るので、余分な関数ですべてをラップするのではなく、このように単純な呼び出しを行うことができます。

于 2014-08-05T09:35:54.283 に答える
2

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

于 2009-06-04T14:48:57.603 に答える
1

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

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

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

于 2012-02-13T22:50:42.997 に答える
1

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

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

このコードは、「待機条件がまだ満たされていない場合は、これらの引数でこの関数を再度呼び出す」ことを示しています。このメソッドを使用して同じ引数をハンドラーに渡し、このコードを効果的に非ポーリングの sleep() (関数の開始時にのみ機能します) にしました。

于 2011-09-26T19:51:33.033 に答える
1

ここでのほとんどのソリューションの問題は、スタックを巻き戻すことです。これは、場合によっては大きな問題になる可能性があります。この例では、イテレータを別の方法で使用して実際の sleepをシミュレートする方法を示します。

この例では、ジェネレーターは独自の を呼び出しているnext()ため、いったん開始すると、それ自体が独立します。

var h = a();
h.next().value.r = h; // That's how you run it. It is the best I came up with

// Sleep without breaking the 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");
}
于 2016-10-13T14:31:04.117 に答える
0

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

于 2012-11-01T11:56:48.407 に答える
0

サーバー側では、 Cでネイティブに実装されているdeasyncメソッドを使用できるため、 イベント ループをブロックしたり、CPU に 100% の負荷をかけたりすることなく、効果的に待機効果を実装できます。sleep()

例:

#!/usr/bin/env node

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

sleep(5000);

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

ただし、純粋なJavaScript 関数が必要な場合(たとえば、ブラウザーによってクライアント側で実行する場合) は、申し訳ありませんが、あなたのpausecomp()関数がそれにアプローチする唯一の方法だと思います。

  1. これにより、関数だけでなく、イベント ループ全体が一時停止します。そのため、他のイベントへの参加はありません。

  2. CPU の負荷を 100% にします。

したがって、ブラウザー スクリプトに必要であり、これらのひどい効果を望まない場合は、関数を何らかの方法で再考する必要があると言わざるを得ません。

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

b)。または、結果を待つ必要がある場合は、Promise の使用に移行する必要があります (もちろん、コールバック地獄 ;-))。

結果が期待されない例:

function myFunc() {

    console.log ("Do some things");

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

    // Returns undefined.
};

myFunc();

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

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);
});
于 2016-10-14T06:12:28.970 に答える
0

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

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

本当にしたい場合は、元の質問に示されているようなforループを使用してスリープ機能をシミュレートできますが、それでは CPU が狂ったように機能します。Web Worker 内では、XMLHttpRequest応答しない IP アドレスに同期させ、適切なタイムアウトを設定するという別の解決策があります。これにより、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!');

于 2015-09-01T04:34:39.663 に答える
0

ソリューションを 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 を実行した後 (Internet Explorer 11 と Chrome 49 でテストしました)、2 つのコンソール ステートメントの間に 3 秒間スリープすることがわかります。コードを伝統的なスタイルと同じくらいきれいに保ちます。

注意が必要なのは、sleepFor ルーチンです。呼び出し元の関数本体を文字列として読み取り、2 つの部分に分割します。上部を取り除き、下部で別の機能を作成します。指定されたミリ秒数待機した後、元のコンテキストと引数を適用して、作成された関数を呼び出します。本来の流れの為、通常通り「戻る」で終了となります。「収穫」のため?正規表現のマッチングに使用されます。必要ですが、まったく役に立ちません。

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

function coroutine3() {
    this.a = 100;
    console.log('coroutine3-1:start');
    if(true) {
        return sleepFor(3000).yield;
    } // <- Raise an 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」関数を待ちます。100 ミリ秒ごとに値をチェックします。追加の引数を渡すことで調整できます。テスト用の coroutine2 を考えてみましょう:

function coroutine2(c) {
    /* Some code 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 the 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 ミリ秒待機します。Coroutine2 は、500 ミリ秒待機した後、ステップ 2 に入ります。その後、coroutine1.a の値が 100 を超えることが検出されると、ステップ 3 に進みます。

変数「a」を保持するコンテキストが 3 つあることに注意してください。1 つは外部で、値は 10 と 11 です。もう 1 つは coroutine1 にあり、値は 100 と 101 です。最後のものは coroutine2 にあり、値は 1、2、3 です。coroutine2 では、ca が来るのも待ちます。 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 code 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 the 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++);

Internet Explorer 11 と Chrome 49 で動作確認済みです。arguments.callee を使用しているため strict モードで実行すると問題が発生する可能性があります。

于 2016-03-28T01:04:34.713 に答える
0

本当にスクリプトを一時停止したい場合は、次のようにします。

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

とにかくループを使用する場合、これはおそらくまさにあなたが望むものであり、いくつかの機能がしばらく待機し、他の機能が正常に実行される疑似マルチスレッドを実現するように変更できます。私はこれを純粋な JavaScript ゲームに常に使用しています。

于 2016-03-31T20:10:35.087 に答える
0

JavaScript はシングルスレッドの実行環境です。そこにあるすべての関数は、たった 1 つのスレッドによって実行されます。「スリープ」を要求するということは、VM インスタンス全体を何ミリ秒も停止させたいということです。これは、JavaScript の世界ではあまり現実的な要求ではないと思います。実行中のスレッドがスリープ状態になると、すべての実行が影響を受けます。

まず、そのスレッドを実際にスリープ状態にすることはできません。何もせずに何らかの作業を行うことによってのみ、そのスレッドをビジー状態に保つことができます。ただし、一部の計算に遅延を追加するだけの場合は、それらの実行を単一の関数コンテキスト内に配置し、その関数内から setTimeout (または、必要に応じて Promise) 内で継続を発生させます。睡眠によって何かを遅らせようとしている場合、それ以外の場合は不可能です。

于 2021-07-06T16:08:38.153 に答える
-1

I use the multithread HTML5 Worker which will be able to abort an synchronous XMLHttpRequest pointing to an unresponsive URL. This does not block the browser.

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

于 2013-10-15T12:40:39.470 に答える
-1

JavaScript関数は一時停止を許可しません。同期 JavaScript では、プロシージャが実装されます。プロシージャは、I/O 操作とスリープ タイムアウトを待ちます。JavaScript 1.7 で使用できます。

デモ:

于 2017-07-10T19:43:40.947 に答える
-2

.htaスクリプトをスリープ状態にする方法を次に示します。これにより、スクリプトが起動したときに、ループで必要に応じて次のコマンドが順番に実行されます。これは本当の睡眠です。スリープ中にプロセッサをビジー状態に保つことはありません。たとえば、プロセッサはスリープ中にページをダウンロードしてレンダリングできます。

一度だけ、コードの先頭近くで、

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

たとえば、1 秒 = 1000 ミリ秒のスリープの場合、次のステートメントを実行します。

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

スクリプトと同じディレクトリにSleep.jsは、次の 1 行を含むファイルがあります。

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

(注意してください;0は括弧ではなく括弧の中にあります。) 後者は、実際にスリープを実行する行です。前のスニペットの引数trueにより、呼び出しが同期されます。前の引数の3は効果がないように見えますが、何らかの引数が必要なので、それtrueが 3 番目の引数です。

Microsoft は、「WScript オブジェクトは、そのプロパティとメソッドを呼び出す前にインスタンス化する必要はなく、常に任意のスクリプト ファイルから使用できる」と述べていますが、これは正しくありません。上記のような独立.jsしたファイルで利用できますが、明らかに.jsファイルによって使用される.htaファイルでは利用できないため、上記のように呼び出された別のファイルにある必要があります。

于 2015-04-10T01:09:13.337 に答える
-2

別の可能な方法は次のとおりです。

var _timer;
clearTimeout(_timer);
_timer = setTimeout(function() {
    // Your code
}, 1000); // Delay for 1 s.
于 2016-03-23T14:17:12.130 に答える
-2

次の 3 つの関数を使用します。

  1. setIntervalループを開始するために呼び出す関数
  2. clearIntervalループを停止するために呼び出し、次にsetTimeoutスリープを呼び出し、最後にsetTimeoutループを再開するためのコールバックとして内で呼び出す関数
  3. 反復回数を追跡し、スリープ回数と最大回数を設定し、スリープ回数に達したらスリープ関数を呼び出しclearInterval、最大回数に達した後に呼び出すループ

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

イベントループ

参考文献

于 2016-07-02T00:25:29.277 に答える
-3

LiveScript (JavaScript にコンパイルされます)では、次のように実行できます。

sleep = (ms, func) -> set-timeout func, ms

console.log "hello-1"
<- sleep 2000ms
console.log "hello-2"
<- sleep 2000ms
console.log "hello-3"
于 2016-04-06T20:28:01.290 に答える
-9

または、これを作成します。

function yourFunction(){

   // Do something
   setInterval(myFunc(), 1000);
   // Do something else
}

function myFunc(){
   return;
}

これは、指定された間隔だけ待機し、何もしない関数を呼び出します。

于 2013-02-15T19:48:37.223 に答える