WindowOrWorkerGlobalScope ミックスインの setTimeout() メソッド (および window.setTimeout の後継) は、指定された遅延の後に関数またはコードの断片を実行するタイマーを設定します。

構文

var timeoutID = scope.setTimeout(function[, delay, param1, param2, ...]);
var timeoutID = scope.setTimeout(function[, delay]);
var timeoutID = scope.setTimeout(code[, delay]);

引数

function
タイマーが満了した後に実行したい 関数
code
関数の代わりに文字列を含める代替構文も許容されており、タイマーが満了したときに文字列をコンパイルして実行します。eval() の使用にリスクがあるのと同じ理由で、この構文は 推奨しません
delay Optional
指定した関数やコードを実行する前に待つタイマーの時間をミリ秒 (1/1000 秒) 単位で指定します。この引数を省略すると値 0 を使用しますので "直ちに" 実行する、より正確に言えばできるだけ早く実行することを意味します。どちらの場合も、実際の遅延が想定より長くなることがあります。後述する 遅延が指定値より長い理由 をご覧ください。
param1, ..., paramN Optional
タイマーが満了したときに、、function または code で指定した関数に渡す追加の引数です。

注記: Internet Explorer 9 およびそれ以前のバージョンでは、最初の構文で関数に渡す追加の引数は動作しないことに注意してください。同様の機能を実現させるには、ポリフィルを使用してください。(ポリフィル を参照)。

戻り値

戻り値 timeoutID は、setTimeout() を呼び出して作成したタイマーを識別する正の整数値です。この値は、タイムアウトをキャンセルするために clearTimeout() へ渡すことができます。

setTimeout()setInterval() は同じ ID プールを共有しており、さらに clearTimeout()clearInterval() は技術的に入れ替えて使用できることを意識すると役に立つでしょう。ただし明快さのために、コードを整備するときは混乱を避けるため、常に一致させるようにするべきです。

同じオブジェクト (window または worker) では、後に setTimeout()setInterval() を呼び出しても timeout ID を再使用しないことが保証されています。ただし、異なるオブジェクトでは別の ID プールを使用します。

以下の例はウェブページに 2 つのシンプルなボタンを置いており、setTimeout() および clearTimeout() のルーチンを実行します。1 番目のボタンを押下すると 2 秒後にアラートダイアログを呼び出すタイムアウトを設定して、clearTimeout() で使用するタイムアウト ID を保存します。2 番目のボタンを押下すると、このタイムアウトをキャンセルできます。

HTML コンテンツ

<p>Live Example</p>
<button onclick="delayedAlert();">2秒後にアラートボックスを表示する</button>
<p></p>
<button onclick="clearAlert();">アラートを事前にキャンセルする</button>

JavaScript コンテンツ

var timeoutID;

function delayedAlert() {
  timeoutID = window.setTimeout(slowAlert, 2000);
}

function slowAlert() {
  alert('それは実に遅かった!');
}

function clearAlert() {
  window.clearTimeout(timeoutID);
}

結果

clearTimeout() の例 もご覧ください。

ポリフィル

コールバック関数に 1 つ以上の引数を渡す必要があるが、setTimeout()setInterval() を使用して追加の引数を渡す機能をサポートしないブラウザー (例えば Internet Explorer 9 およびそれ以前) で動作しなければならない場合は、HTML5 標準の引数渡し機能を可能にする以下のポリフィルを追加するとよいでしょう。このコードをスクリプトの先頭に追加してください:

/*\
|*|
|*|  Polyfill which enables the passage of arbitrary arguments to the
|*|  callback functions of JavaScript timers (HTML5 standard syntax).
|*|
|*|  https://developer.mozilla.org/en-US/docs/DOM/window.setInterval
|*|
|*|  Syntax:
|*|  var timeoutID = window.setTimeout(func, delay[, param1, param2, ...]);
|*|  var timeoutID = window.setTimeout(code, delay);
|*|  var intervalID = window.setInterval(func, delay[, param1, param2, ...]);
|*|  var intervalID = window.setInterval(code, delay);
|*|
\*/

(function() {
  setTimeout(function(arg1) {
    if (arg1 === 'test') {
      // feature test is passed, no need for polyfill
      return;
    }
    var __nativeST__ = window.setTimeout;
    window.setTimeout = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) {
      var aArgs = Array.prototype.slice.call(arguments, 2);
      return __nativeST__(vCallback instanceof Function ? function() {
        vCallback.apply(null, aArgs);
      } : vCallback, nDelay);
    };
  }, 0, 'test');

  var interval = setInterval(function(arg1) {
    clearInterval(interval);
    if (arg1 === 'test') {
      // feature test is passed, no need for polyfill
      return;
    }
    var __nativeSI__ = window.setInterval;
    window.setInterval = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) {
      var aArgs = Array.prototype.slice.call(arguments, 2);
      return __nativeSI__(vCallback instanceof Function ? function() {
        vCallback.apply(null, aArgs);
      } : vCallback, nDelay);
    };
  }, 0, 'test');
}())

IE 限定の fix

IE 9 およびそれ以前を含む、他のすべてのモバイルブラウザーやデスクトップブラウザーで完全に目立たないハックが必要である場合は、以下の JavaScript 条件付きコメントを使用できます:

/*@cc_on
  // conditional IE < 9 only fix
  @if (@_jscript_version <= 9)
  (function(f){
     window.setTimeout = f(window.setTimeout);
     window.setInterval = f(window.setInterval);
  })(function(f){return function(c,t){var a=[].slice.call(arguments,2);return f(function(){c instanceof Function?c.apply(this,a):eval(c)},t)}});
  @end
@*/

あるいは IE の HTML 条件機能による、とてもクリーンな方法を使用します:

<!--[if lte IE 9]><script>
(function(f){
window.setTimeout=f(window.setTimeout);
window.setInterval=f(window.setInterval);
})(function(f){return function(c,t){
var a=[].slice.call(arguments,2);return f(function(){c instanceof Function?c.apply(this,a):eval(c)},t)}
});
</script><![endif]-->

回避策

もうひとつの方法は、コールバックに無名関数を使用することです。ただし、この方法は少し多くコストがかかります。例:

var intervalID = setTimeout(function() { myFunc('one', 'two', 'three'); }, 1000);

上記の例は、アロー関数 を使用して以下のように記述できます:

var intervalID = setTimeout(() => { myFunc('one', 'two', 'three'); }, 1000);

さらに、関数の bind を使用する方法もあります。例:

setTimeout(function(arg1){}.bind(undefined, 10), 1000);

"this" 問題

setTimeout() にメソッド (そういうことならほかの関数も) を渡すとき、コードが実行される際の this の値が想定とは異なるかもしれません。この問題は JavaScript リファレンス でより詳細に説明されています。

説明

setTimeout() によって実行されるコードは、setTimeout が呼び出された関数とは別の実行コンテキスト内から呼び出されます。呼び出された関数に this キーワードを設定する通常の規則を適用して、呼び出しあるいは bindthis を設定しなければ、非 strict モードでは global (または window)、strict モードでは undefined になります。これは、setTimeout が呼び出された関数の this 値と同じにはなりません。

注記: setTimeout コールバックの既定の this の値は、strict モードであっても undefined ではなく、window オブジェクトです。

以下の例をご覧ください:

myArray = ['zero', 'one', 'two'];
myArray.myMethod = function (sProperty) {
    alert(arguments.length > 0 ? this[sProperty] : this);
};

myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"

myMethod を呼び出したときに、呼び出しによって thismyArray に設定されますので、関数内で this[sProperty]myArray[sProperty] と等価です。しかし、以下のコードでは動作が異なります:

setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second
setTimeout(myArray.myMethod, 1500, '1'); // prints "undefined" after 1.5 seconds

myArray.myMethod 関数を setTimeout に渡しており、関数が呼び出されると this が前のように設定されず、既定値の window オブジェクトになります。Array の forEach や reduce などのメソッドにあるような、thisArg を setTimeout に渡すオプションもありません。また以下のように、this を設定するために call を使用する方法も動作しません。

setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error

考えられる解決策

この問題の一般的な解決策は、this に必要な値を設定するラッパー関数を使用することです:

setTimeout(function(){myArray.myMethod()}, 2000); // prints "zero,one,two" after 2 seconds
setTimeout(function(){myArray.myMethod('1')}, 2500); // prints "one" after 2.5 seconds

代わりにアロー関数も使用できます:

setTimeout(() => {myArray.myMethod()}, 2000); // prints "zero,one,two" after 2 seconds
setTimeout(() => {myArray.myMethod('1')}, 2500); // prints "one" after 2.5 seconds

他に考えられる "this" 問題の解決策として、本来の setTimeout() および setInterval() グローバル関数を、this オブジェクトを渡せるようにして、コールバックで Function.prototype.call を使用して設定するように置き換える方法があります。例えば:

// Enable setting 'this' in JavaScript timers
 
var __nativeST__ = window.setTimeout, 
    __nativeSI__ = window.setInterval;
 
window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
  var oThis = this, 
      aArgs = Array.prototype.slice.call(arguments, 2);
  return __nativeST__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};
 
window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
  var oThis = this,
      aArgs = Array.prototype.slice.call(arguments, 2);
  return __nativeSI__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};
注記: これら 2 つの置き換えにより、IE のタイマーで HTML5 標準の、コールバック関数に任意の引数を渡すことも可能になります。よって、ポリフィルとしても使用できます。Callback arguments の節をご覧ください。

新機能のテスト:

myArray = ['zero', 'one', 'two'];
myArray.myMethod = function (sProperty) {
    alert(arguments.length > 0 ? this[sProperty] : this);
};

setTimeout(alert, 1500, 'Hello world!'); // the standard use of setTimeout and setInterval is preserved, but...
setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2.5 seconds
注記: JavaScript 1.8.5 で、関数のすべての呼び出しに対して this の値を設定する Function.prototype.bind() メソッドを導入しました。これにより、コールバックで this の値を設定するためにラッパー関数を使用しなければならない状況を回避できます。

bind() の使用例:

myArray = ['zero', 'one', 'two'];
myBoundMethod = (function (sProperty) {
    console.log(arguments.length > 0 ? this[sProperty] : this);
}).bind(myArray);

myBoundMethod(); // prints "zero,one,two" because 'this' is bound to myArray in the function
myBoundMethod(1); // prints "one"
setTimeout(myBoundMethod, 1000); // still prints "zero,one,two" after 1 second because of the binding
setTimeout(myBoundMethod, 1500, "1"); // prints "one" after 1.5 seconds

注記

clearTimeout() を使ってタイムアウトを中止することができます。もし関数を繰返し (すなわち、N ミリ秒ごとに) 呼びたいなら、setInterval() を使うことを考慮してください。

文字列リテラルの使用

関数の代わりに、文字列を setTimeout() に渡すと、eval を使うのと同様の危険性があります。

// 推奨
window.setTimeout(function() {
    alert('Hello World!');
}, 500);

// 非推奨
window.setTimeout("alert('Hello World!');", 500);

setTimeout に渡した文字列はグローバルコンテキストで評価されます。そのため、setTimeout() が呼び出されたコンテキストのローカルシンボルは、文字列を評価したコードからは利用できません。

遅延が指定値より長い理由

タイムアウトが満了するまでに予想より長い時間がかかる理由は複数あります。このセクションでは、もっとも一般的な理由を説明します。

タイムアウトを 4ms 以上に制限する

現代のブラウザーは、setTimeout()setInterval() がコールバックのネスト (ネストの深さが少なくとも数段階ある) によって連続的に呼び出された、あるいは連続的なインターバルが数回発生した後に呼び出されたときに、少なくとも 4 ミリ秒ごとに呼び出されるように制限をかけます。例えば:

function cb() { f(); setTimeout(cb, 0); }
setTimeout(cb, 0);
setInterval(f, 0);

Chrome および Firefox では、5 回目の連続的なコールバックの呼び出しで制限をかけます。また Safar は 6 回目、Edge は 3 回目で制限をかけます。Gecko は バージョン 56 で、setInterval() で制限を始めました (後述のとおり setTimeout() は以前から行っていました)。

歴史的に 一部のブラウザー (例えば Firefox) は、あらゆる場所から呼び出された setInterval()、あるいはネストの深さが少なくとも数段階ある setTimeout() が呼び出されたときの制限を、若干異なる動作で実装しています。。

0 ms タイマーをモダンブラウザーで実装するには、ここで説明されている window.postMessage() を利用できます。

注記: 最小遅延である DOM_MIN_TIMEOUT_VALUE は 4 ms (Firefox の dom.min_timeout_value の設定に保存されています) であり、DOM_CLAMP_TIMEOUT_NESTING_LEVEL は 5 です。

注記: 4 ms は HTML5 の仕様で標準化されています。 そして、2010 年以降にリリースされたブラウザー間で一貫しています。(Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) 以前では、ネストされた setTimeout の最小値は 10 ms でした。

非アクティブタブのタイムアウトを 1000 ms 以上に制限する

バックグラウンドのタブによる負荷 (およびバッテリー消費) を軽減するため、アクティブ状態でないタブでのタイマーの呼び出しは、1 秒 (1000 ms) あたり 1 回までとなります。

Firefox はこの動作をバージョン 5 (バグ 633421 を参照。1000 ms の定数は設定項目 dom.min_background_timeout_value で変更できます) から、Chrome はこの動作をバージョン 11 (crbug.com/66078) から実装しています。

Android 版 Firefox は バグ 736602 によって、Firefox 14 からバックグラウンドタブで 15 分のタイムアウト値を使用しており、またバックグラウンドタブを完全にアンロードすることもできます。

Firefox 50 では、Web Audio API の AudioContext が音声を再生中であればバックグラウンドタブの制限を行いません。さらに Firefox 51 では、音声を再生していなくても AudioContext を提供していれば、バックグラウンドタブの制限を行わないように改良しました。これによりタブがバックグラウンドであるときに、楽譜を基に音楽を再生するアプリで拍子が合わない、あるいは音楽が正しく同期しないといった問題が解決します。

トラッキングスクリプトのタイムアウトを制限する

Firefox 55 より、トラッキングスクリプト (例えば Google Analytics や、TP リスト によって Firefox がトラッキングスクリプトであると認識するスクリプトの URL) にさらなる制限を課します。フォアグラウンドで実行しているとき、最小遅延の制限は 4ms のままです。しかしバックグラウンドのタブでは、最小遅延を 10000ms または 10 秒に制限します。これはドキュメントが最初に読み込まれてから 30 秒後に発効します。

この動作を制御する設定項目は以下のとおりです:

  • dom.min_tracking_timeout_value: 4
  • dom.min_tracking_background_timeout_value: 10000
  • dom.timeout.tracking_throttling_delay: 30000

タイムアウトの遅延

前出の "制限" に加えて、ページ内 (またはOSやブラウザー自身) の他のタスクの処理に時間がかかると、タイムアウトは遅れます。注目すべき重要なケースとして、setTimeout() を呼び出したスレッドが終了するまで関数やコードスニペットを実行できないことが挙げられます。例えば:

function foo() {
  console.log('foo has been called');
}
setTimeout(foo, 0);
console.log('After setTimeout');

このコードは、コンソールへ以下のように出力します:

After setTimeout
foo has been called

これは setTimeout を遅延 0 で呼び出したとしても、直ちに実行するのではなくキューに載せて、次の機会に実行するようスケジューリングされるためです。現在実行中のコードはキューにある関数を実行する前に完了しなければならず、このために実行結果の順序が想定どおりにならない場合があります。

最大遅延時間

Internet Explorer、Chrome、Safari、Firefox を含むブラウザーは、内部で遅延時間を 32 ビット符号付き整数値で保存します。このため 2147483647 (約 24.8 日) より大きな遅延時間を使用すると整数値がオーバーフローして、その結果直ちに実行されるタイムアウトになります。

仕様

仕様書 策定状況 コメント
HTML Living Standard
WindowOrWorkerGlobalScope.setTimeout() の定義
現行の標準 最新の仕様で、メソッドを WindowOrWorkerGlobalScope ミックスインに移動。
HTML Living Standard
WindowTimers.setTimeout() の定義
現行の標準 最初期の定義 (DOM Level 0)

ブラウザー実装状況

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
基本対応1 あり

1

521

441
Supports parameters for callback あり あり あり10 あり ?
Throttling of tracking timeout scripts ? ?55 ? ? ?
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
基本対応11 あり

4

521

61 ?
Supports parameters for callback ? ? ? ? ? ? ?
Throttling of tracking timeout scripts ? ? ?55 ? ? ?

1. setInterval now defined on WindowOrWorkerGlobalScope mixin.

関連情報