初めて遅延することなくsetInterval関数を実行する


339

それはsetIntervalすぐにメソッドを実行し、タイマーで実行するようにJavaScript のメソッドを設定する方法があります


4
ネイティブではありませんが。あなたはfunction一度電話をかけ、それからsetInterval()
Mrchief

回答:


519

初めて関数を自分で直接呼び出すのが最も簡単です。

foo();
setInterval(foo, delay);

ただし、回避するのには十分な理由があります。setInterval特に状況によっては、setIntervalイベントの負荷全体が遅延なしでお互いの直後に到着する場合があります。もう1つの理由は、ループを停止する場合は明示的に呼び出すclearInterval必要があるためsetIntervalです。つまり、元の呼び出しから返されたハンドルを覚えておく必要があります。

したがって、代わりの方法は、代わりfooに次の呼び出しを使用して自身をトリガーすることですsetTimeout

function foo() {
   // do stuff
   // ...

   // and schedule a repeat
   setTimeout(foo, delay);
}

// start the cycle
foo();

これにより、少なくともdelay呼び出しの間に間隔があることが保証されます。また、必要に応じてループをキャンセルするのも簡単になりsetTimeoutます。ループの終了条件に達したときに呼び出さないだけです。

さらに良いのは、すぐに呼び出される関数式ですべてをラップして、関数を作成し、上記のように再度呼び出してループを自動的に開始することです。

(function foo() {
    ...
    setTimeout(foo, delay);
})();

関数を定義し、サイクルをすべて一度に開始します。


5
なぜあなたは好きsetTimeoutですか?
サンヒュンリー

19
@Sangdolは、タイマーイベントが未処理のままになっている場合に、タイマーイベントが「スタック」しないようにするためです。状況によっては、大量のsetIntervalイベントが遅延なしでお互いの直後に到着する場合があります。
アルニタク2012年

8
疲れているときにスタックに投稿できないようなテストがあるはずです
James

3
setTimeoutメソッドを使用する場合、関数を停止するにはどうすればよいですか?
Gaurav Bhor、

6
@DaveMungerいいえ、それは本当に再帰的ではないためです-「疑似再帰的」だけです。「再帰的」呼び出しは、ブラウザーがイベントループに戻るまで発生しません。その時点で、呼び出しスタックは完全に巻き戻されます。
Alnitak 2015年

209

私があなたを正しく理解しているかどうかはわかりませんが、次のようなことは簡単にできます。

setInterval(function hello() {
  console.log('world');
  return hello;
}(), 5000);

これを行う方法はいくつもありますが、それが私が考えることができる最も簡潔な方法です。


16
これは、すぐに実行され、それ自体を返す名前付き関数であるため、すばらしい回答です。まさに私が探していたもの。
jmort253 2014

41
間違いなくクールなソリューションですが、将来的に読む人を混乱させる可能性があります。
Deepak Joy

4
「こんにちは」という名前を付ける必要はありません。代わりに、arguments.calleeを返し、無名関数と同じにすることができます
JochenJung

10
@JochenJung arguments.calleeはES5ストリクトモードでは使用できません
Alnitak

3
これは、他の言語から来たほとんどの新しいJSプログラマーを混乱させる種類のJavascriptコードです。会社にJS担当者が多くなく、仕事の安全を確保したい場合は、このようなものをたくさん書いてください。
Ian

13

同じ問題が原因でこの質問に出くわしましたが、まったく同じように動作する必要がある場合、どの回答も役に立ちませんが、最初に関数がすぐに呼び出されるという唯一の違いがあります。setInterval()

これがこの問題に対する私の解決策です:

function setIntervalImmediately(func, interval) {
  func();
  return setInterval(func, interval);
}

このソリューションの利点:

  • 既存のコードを使用してsetInterval、置換によって簡単に適合させることができます
  • 厳密モードで動作します
  • 既存の名前付き関数とクロージャーで動作します
  • 戻り値を使用してclearInterval()後で渡すことができます

例:

// create 1 second interval with immediate execution
var myInterval = setIntervalImmediately( _ => {
        console.log('hello');
    }, 1000);

// clear interval after 4.5 seconds
setTimeout( _ => {
        clearInterval(myInterval);
    }, 4500);

生意気であるために、本当に使用する必要がある場合setIntervalは、元のを置き換えることもできますsetInterval。したがって、既存のコードの前にこれを追加する場合、コードを変更する必要はありません。

var setIntervalOrig = setInterval;

setInterval = function(func, interval) {
    func();
    return setIntervalOrig(func, interval);
}

それでも、上記のすべての利点がここに適用されますが、代用する必要はありません。


オブジェクトをsetTimeout返すため、私はソリューションよりもこのソリューションを好みsetIntervalます。多分、後のコードで、したがって、現在の時点で未定義の関数を呼び出す避けるために、私は最初の関数呼び出しラップsetTimeout:このような機能setTimeout(function(){ func();},0);最初の関数は、現在の処理サイクル後に呼び出され、またあるすぐに、しかしですより多くのエラーが証明されました。
pensan

8

setInterval()その振る舞いを提供する関数でラップすることができます:

function instantGratification( fn, delay ) {
    fn();
    setInterval( fn, delay );
}

...その後、次のように使用します。

instantGratification( function() {
    console.log( 'invoked' );
}, 3000);

5
setIntervalが返すものを返す必要があると思います。それ以外の場合は、clearIntervalを使用できないためです。
Henrik R

5

ここに、必要に応じてそれをきれいにするラッパーがあります:

(function() {
    var originalSetInterval = window.setInterval;

    window.setInterval = function(fn, delay, runImmediately) {
        if(runImmediately) fn();
        return originalSetInterval(fn, delay);
    };
})();

setIntervalの3番目の引数をtrueに設定すると、setIntervalを呼び出した直後に初めて実行されます。

setInterval(function() { console.log("hello world"); }, 5000, true);

または、3番目の引数を省略すると、元の動作が保持されます。

setInterval(function() { console.log("hello world"); }, 5000);

一部のブラウザーは、このラッパーが考慮しないsetIntervalの追加の引数をサポートしています。これらはめったに使用されないと思いますが、必要な場合は覚えておいてください。


9
仕様が変更されたときに、他の共存するコードが壊れる可能性があるため、ネイティブブラウザー関数のオーバーライドはひどいです。実際には、たsetIntervalは現在、より多くのパラメータがあります。developer.mozilla.org/en-US/docs/Web/API/WindowTimers/...
アクセル・コスタスペーニャ

2

thisまるでそれが矢の関数であるかのように誰かが外側を内側に持ってくる必要があるからです。

(function f() {
    this.emit("...");
    setTimeout(f.bind(this), 1000);
}).bind(this)();

上記の生成ゴミが気になる場合は、代わりにクロージャーを作成できます。

(that => {
    (function f() {
        that.emit("...");
        setTimeout(f, 1000);
    })();
})(this);

または、コードに応じて@autobindデコレータの使用を検討しください。


1

次の順序で関数を呼び出すことをお勧めします

var _timer = setInterval(foo, delay, params);
foo(params)

特定の条件で行い_timerたい場合は、fooに渡すこともできclearInterval(_timer)ます

var _timer = setInterval(function() { foo(_timer, params) }, delay);
foo(_timer, params);

これについて詳しく説明していただけますか?
Polyducks 2018

2回目の呼び出しからタイマーを設定します。初めて、直接fnを直接呼び出すだけです。
Jayant Varshney、2018

1

これは、すべての混乱のない初心者向けのシンプルなバージョンです。関数を宣言して呼び出し、間隔を開始するだけです。それでおしまい。

//Declare your function here
function My_Function(){
  console.log("foo");
}    

//Call the function first
My_Function();

//Set the interval
var interval = window.setInterval( My_Function, 500 );


1
それが、最初の数行で受け入れられた答えが正確に行うことです。この答えはどのように新しい何かを追加しますか?
Dan Dascalescu 2018

受け入れられた答えは、これを行わないことです。受け入れられた回答への私の回答は、それがまだ有効な方法である理由を説明しています。OPは特に、最初の呼び出しでsetIntervalの関数を呼び出すように求めますが、受け入れられた回答は、setTimeoutの利点について話します。
Polyducks 2018年

0

この問題を解決するために、ページが読み込まれた後、最初に関数を実行します。

function foo(){ ... }

window.onload = function() {
   foo();
};

window.setInterval(function()
{
    foo(); 
}, 5000);

0

firstIntervalと呼ばれる便利なnpmパッケージがあります(完全な開示、私のものです)。

ここでの例の多くにはパラメータ処理が含まれておらず、setInterval大規模なプロジェクトでのデフォルトの動作を変更することは悪いことです。ドキュメントから:

このパターン

setInterval(callback, 1000, p1, p2);
callback(p1, p2);

と同じです

firstInterval(callback, 1000, p1, p2);

ブラウザーを使い古していて依存関係を望まない場合は、コードから簡単にカットアンドペーストできます。


0

// YCombinator
function anonymous(fnc) {
  return function() {
    fnc.apply(fnc, arguments);
    return fnc;
  }
}

// Invoking the first time:
setInterval(anonymous(function() {
  console.log("bar");
})(), 4000);

// Not invoking the first time:
setInterval(anonymous(function() {
  console.log("foo");
}), 4000);
// Or simple:
setInterval(function() {
  console.log("baz");
}, 4000);

これはとても複雑なので、もっと簡単に説明しましょう。

function hello(status ) {    
  console.log('world', ++status.count);
  
  return status;
}

setInterval(hello, 5 * 1000, hello({ count: 0 }));


これは非常に過剰に設計されています。
Polyducks 2018

0

非常に小さい初期遅延時間(たとえば100)を設定し、関数内で希望の遅延時間に設定できます。

var delay = 100;

function foo() {
  console.log("Change initial delay-time to what you want.");
  delay = 12000;
  setTimeout(foo, delay);
}


-2

関数の即時非同期呼び出しには問題があります。標準のsetTimeout / setIntervalは、直接0に設定した場合でも、数ミリ秒程度の最小タイムアウトがあるためです。これは、ブラウザー固有の作業が原因です。

Chrome、Safari、Operaで動作するREALゼロ遅延のコードの例

function setZeroTimeout(callback) {
var channel = new MessageChannel();
channel.port1.onmessage = callback;
channel.port2.postMessage('');
}

あなたはここでより多くの情報を見つけることができます

また、最初の手動呼び出しの後、関数を使用して間隔を作成できます。


-10

実際には最速のことです

interval = setInterval(myFunction(),45000)

これはmyfunctionを呼び出し、それから45秒ごとに再びそれを実行します。

interval = setInterval(myfunction, 45000)

それは呼ばれませんが、それだけをスケジュールします


どこから手に入れたの?
Ken Sharp

2
これが機能するのmyFunction()は、それ自体が戻る場合のみです。代わりに、setIntervalそれによって呼び出されるように各関数を変更することはsetInterval、他の回答が提案しているように一度ラップするより良いアプローチです。
イェンスワース
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.