web-dev-qa-db-ja.com

コード実行の同期遅延

なんらかの遅延後に5000ミリ秒後に実行する必要のあるコードがあります。現在、私はsetTimeoutを使用していますが、非同期であり、実行がその戻りを待機するようにしています。私は以下を使ってみました:

function pauseComp(ms) 
 {
     var curr = new Date().getTime();
     ms += curr;
     while (curr   < ms) {
         curr = new Date().getTime();
     }
 } 

しかし、私が遅延させたいコードはraphaeljsを使用していくつかのオブジェクトを描画しており、表示はまったくスムーズではありません。 doTimeoutプラグインを使用しようとしています。遅延と遅延するコードの両方がループにあるため、遅延は1回だけ必要です。 IDは必要ないので、使用していません。例えば:

for(i; i<5; i++){ $.doTimeout(5000,function(){
         alert('hi');  return false;}, true);}

これは、最初のHiを与える前に5秒間待機し、その後のループ反復では、最初の直後にアラートを表示します。私がしたいことは、5秒間待って再度警告を発し、その後警告を発することです。

ヒント/提案は大歓迎です!

31
kavita

これと同じくらい良い、受け入れられた回答のバリエーション。

また、私はsetTimeoutと非同期関数呼び出しを優先することの警告に同意しますが、たとえば、テストを構築するときは、同期待機コマンドが必要なだけです...

function wait(ms) {
    var start = Date.now(),
        now = start;
    while (now - start < ms) {
      now = Date.now();
    }
}

秒でそれが必要な場合は、whileチェックでstart msを1000で割ります...

46
ThinkBonobo

新しいasync/await構文を利用したい場合は、set timeoutをpromiseに変換して、それを待つことができます。

function wait(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("Done waiting");
      resolve(ms)
    }, ms )
  })
}  

(async function Main() {
  console.log("Starting...")
  await wait(5000);
  console.log("Ended!")
})();
6

JavaScriptはシングルスレッド言語です。 setTimeoutと同期処理を組み合わせることはできません。何が起こるかというと、タイマーが切れますが、JSエンジンは現在のスクリプトが完了するまで結果の処理を待ちます。

同期メソッドが必要な場合は、メソッドを直接呼び出すだけです!

SetTimeoutの後に何かを処理したい場合は、それを含めるか、timeout関数から呼び出します。

5
OverZealous

タイムアウト以外のループ(時間をチェックするか、1000000までカウントする)は、ブラウザをロックするだけです。 setTimeout(または$.doTimeoutプラグイン)が最適です。

ご存知のように、ループは継続する前に前のタイムアウトが発生するのを待機しないため、ループ内でタイムアウトを作成しても機能しません。次のようなものを試してください:

// Generic function to execute a callback a given number
// of times with a given delay between each execution
function timeoutLoop(fn, reps, delay) {
  if (reps > 0)
    setTimeout(function() {
                 fn();
                 timeoutLoop(fn, reps-1, delay);
               }, delay);
}

// pass your function as callback
timeoutLoop(function() { alert("Hi"); },
            5,
            5000);

(これをすばやくまとめたので、機能すると確信していますが、たとえば、「ループ」内で、コールバック関数にインデックス値を渡して、独自のコードがどの反復を知っているかを確認できますそれは次第です。しかし、うまくいけば、それがあなたを始めるでしょう。)

3
nnnnnn

簡単な同期タイムアウト機能を作りました。コールバックと非コールバックの2つの異なる方法で機能します。

関数:

function wait(ms, cb) {
  var waitDateOne = new Date();
  while ((new Date()) - waitDateOne <= ms) {
    //Nothing
  }
  if (cb) {
    eval(cb);
  }
}

コールバックの例:

wait(5000,"doSomething();");

非コールバックの例:

console.log("Instant!");
wait(5000);
console.log("5 second delay");
2
andrew65952

JQuery doTimeoutプラグインの使用方法は次のとおりです

jQuery('selector').doTimeout( [ id, ] delay, callback [, arg ... ] );

docs から:「コールバックがtrueを返す場合、doTimeoutループは、遅延後に再度実行され、コールバックが非真の値を返すまでポーリングループを作成します。 "

var start = Date.now();
console.log("start: ", Date.now() - start);
var i = 0;
$.doTimeout('myLoop', 5000, function() {
  console.log(i+1, Date.now() - start);
  ++i;
  return i == 5 ? false : true;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-dotimeout/1.0/jquery.ba-dotimeout.min.js"></script>
0
user2314737

ノードソリューション

Fs.existsSync()を使用して遅延させる

const fs = require('fs');
const uuidv4 = require('uuid/v4');

/**
 * Tie up execution for at-least the given number of millis.  This is not efficient.
 * @param millis Min number of millis to wait
 */
function sleepSync(millis) {
    if (millis <= 0) return;
    const proceedAt = Date.now() + millis;
    while (Date.now() < proceedAt) fs.existsSync(uuidv4());
}
0
Peter L