--- title: WindowOrWorkerGlobalScope.setTimeout() slug: Web/API/setTimeout tags: - API - HTML DOM - Intervals - JavaScript timers - MakeBrowserAgnostic - Method - NeedsCompatTable - NeedsMarkupWork - NeedsUpdate - Reference - Timers - WindowOrWorkerGlobalScope - setTimeout translation_of: Web/API/WindowOrWorkerGlobalScope/setTimeout original_slug: Web/API/WindowOrWorkerGlobalScope/setTimeout ---
setTimeout()
は {{domxref("WindowOrWorkerGlobalScope")}} ミックスインのメソッド (および Window.setTimeout()
の後継) で、時間切れになると関数または指定されたコードの断片を実行するタイマーを設定します。
var timeoutID = scope.setTimeout(function[, delay, arg1, arg2, ...]); var timeoutID = scope.setTimeout(function[, delay]); var timeoutID = scope.setTimeout(code[, delay]);
function
code
delay
{{optional_inline}}arg1, ..., argN
{{optional_inline}}function
で指定された関数に渡す追加の引数です。注: Internet Explorer 9 およびそれ以前のバージョンでは、最初の構文で関数に渡す追加の引数は動作しないことに注意してください。同様の機能を実現させるには、ポリフィルを使用してください。({{anch("Polyfill", "ポリフィル")}} を参照)。
返される timeoutID
は正の整数値で、 setTimeout()
を呼び出して作成したタイマーを識別します。この値を {{domxref("WindowOrWorkerGlobalScope.clearTimeout","clearTimeout()")}} へ渡すことで、タイムアウトを取り消すことができます。
setTimeout()
と {{domxref("WindowOrWorkerGlobalScope.setInterval", "setInterval()")}} は同じ ID プールを共有しており、さらに clearTimeout()
と {{domxref("WindowOrWorkerGlobalScope.clearInterval", "clearInterval()")}} は技術的に入れ替えて使用できることを意識すると役に立つかもしれません。ただし明確さのために、コードを整備するときは混乱を避けるため、常に一致させるようにするべきです。
同じオブジェクト (ウィンドウやワーカー) では、後に setTimeout()
や setInterval()
を呼び出しても タイムアウト ID を再使用しないことが保証されています。ただし、別なオブジェクトでは別の ID プールを使用します。
以下の例はウェブページに 2 つのシンプルなボタンを置いており、setTimeout()
および clearTimeout()
のルーチンを実行します。1 番目のボタンを押下すると 2 秒後にアラートダイアログを呼び出すタイムアウトを設定して、clearTimeout()
で使用するタイムアウト ID を保存します。2 番目のボタンを押下すると、このタイムアウトをキャンセルできます。
<p>Live Example</p> <button onclick="delayedAlert();">2秒後にアラートボックスを表示する</button> <p></p> <button onclick="clearAlert();">アラートを事前にキャンセルする</button>
var timeoutID; function delayedAlert() { timeoutID = window.setTimeout(window.alert, 2*1000, '本当に遅い!'); } function clearAlert() { window.clearTimeout(timeoutID); }
{{EmbedLiveSample('Example')}}
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[, arg1, arg2, ...]); |*| var timeoutID = window.setTimeout(code, delay); |*| var intervalID = window.setInterval(func, delay[, arg1, arg2, ...]); |*| 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 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);
setTimeout()
にメソッド (そういうことならほかの関数も) を渡すとき、コードが実行される際の this
の値が想定とは異なるかもしれません。この問題は JavaScript リファレンス でより詳細に説明されています。
setTimeout()
によって実行されるコードは、 setTimeout
が呼び出された関数とは別の実行コンテキスト内から呼び出されます。呼び出された関数に this
キーワードを設定する通常の規則を適用して、呼び出しあるいは bind
で this
を設定しなければ、非 strict モードでは global
(または window
)、strict モードでは undefined になります。これは、setTimeout
が呼び出された関数の this
値と同じにはなりません。
注: setTimeout
コールバックの既定の this
の値は、厳格モードであっても 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
を呼び出したときに、呼び出しによって this
が myArray
に設定されますので、関数内で this[sProperty]
は myArray[sProperty]
と等価です。しかし、以下のコードでは動作が異なります。
setTimeout(myArray.myMethod, 1.0*1000); // 1秒後に "[object Window]" と表示 setTimeout(myArray.myMethod, 1.5*1000, '1'); // 1.5秒後に "undefined" と表示
myArray.myMethod
関数を setTimeout
に渡しており、関数が呼び出されると this
が前のように設定されず、既定値の window
オブジェクトになります。Array の forEach や reduce などのメソッドにあるような、thisArg
を setTimeout に渡すオプションもありません。また以下のように、this
を設定するために call
を使用する方法も動作しません。
setTimeout.call(myArray, myArray.myMethod, 2.0*1000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object" setTimeout.call(myArray, myArray.myMethod, 2.5*1000, 2); // same error
この問題の一般的な解決策は、this
に必要な値を設定するラッパー関数を使用することです:
setTimeout(function(){myArray.myMethod()}, 2.0*1000); // prints "zero,one,two" after 2 seconds setTimeout(function(){myArray.myMethod('1')}, 2.5*1000); // prints "one" after 2.5 seconds
代わりにアロー関数も使用できます。
setTimeout(() => {myArray.myMethod()}, 2.0*1000); // prints "zero,one,two" after 2 seconds setTimeout(() => {myArray.myMethod('1')}, 2.5*1000); // 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); };
新機能のテスト:
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, 2.0*1000); // prints "zero,one,two" after 2 seconds setTimeout.call(myArray, myArray.myMethod, 2.5*1000, 2); // prints "two" after 2.5 seconds
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, 1.0*1000); // still prints "zero,one,two" after 1 second because of the binding setTimeout(myBoundMethod, 1.5*1000, "1"); // prints "one" after 1.5 seconds
タイムアウトは {{domxref("WindowOrWorkerGlobalScope.clearTimeout","clearTimeout()")}} を使って中止することができます。
もし関数を繰返し (例えば、 N ミリ秒ごとに) 呼び出したいなら、 {{domxref("WindowOrWorkerGlobalScope.setInterval()","setInterval()")}} を使うことを検討してください。
関数の代わりに文字列を setTimeout()
に渡すと、eval を使うのと同様の問題が発生します。
// 推奨 window.setTimeout(function() { alert('Hello World!'); }, 500); // 非推奨 window.setTimeout("alert('Hello World!');", 500);
setTimeout
に渡した文字列はグローバルコンテキストで評価されます。そのため、setTimeout()
が呼び出されたコンテキストのローカルシンボルは、文字列を評価したコードからは利用できません。
タイムアウトが満了するまでに予想より長い時間がかかる理由は複数あります。このセクションでは、もっとも一般的な理由を説明します。
現代のブラウザーは、setTimeout()
や {{domxref("WindowOrworkerGlobalScope.setInterval","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 タイマーをモダンブラウザーで実装するには、ここで説明されている {{domxref("window.postMessage()")}} を利用できます。
注: 最小遅延である DOM_MIN_TIMEOUT_VALUE
は 4 ms (Firefox の dom.min_timeout_value
の設定に保存されています) であり、DOM_CLAMP_TIMEOUT_NESTING_LEVEL
は 5 です。
注: 4 ms は HTML5 の仕様で標準化されています。 そして、2010 年以降にリリースされたブラウザー間で一貫しています。{{geckoRelease("5.0")}} 以前では、ネストされた setTimeout の最小値は 10 ms でした。
バックグラウンドのタブによる負荷 (およびバッテリー消費) を軽減するため、アクティブ状態でないタブでのタイマーの呼び出しは、1 秒 (1,000 ms) あたり 1 回までとなります。
Firefox はこの動作をバージョン 5 ({{bug(633421)}} を参照。1000 ms の定数は設定項目 dom.min_background_timeout_value
で変更できます) から、Chrome はこの動作をバージョン 11 (crbug.com/66078) から実装しています。
Android 版 Firefox は {{bug(736602)}} によって、 Firefox 14 からバックグラウンドタブで 15 分のタイムアウト値を使用しており、またバックグラウンドタブを完全にアンロードすることもできます。
Firefox 50 では、 Web Audio API の {{domxref("AudioContext")}} が音声を再生中であればバックグラウンドタブの制限を行いません。さらに Firefox 51 では、音声を再生していなくても {{domxref("AudioContext")}} を提供していれば、バックグラウンドタブの制限を行わないように改良しました。これによりタブがバックグラウンドであるときに、楽譜を基に音楽を再生するアプリで拍子が合わない、あるいは音楽が正しく同期しないといった問題が解決します。
Firefox 55 より、トラッキングスクリプト (例えば Google Analytics や、TP リスト によって Firefox がトラッキングスクリプトであると認識するスクリプトの URL) にさらなる制限を課します。フォアグラウンドで実行しているとき、最小遅延の制限は 4ms のままです。しかしバックグラウンドのタブでは、最小遅延を 10,000ms または 10 秒に制限します。これはドキュメントが最初に読み込まれてから 30 秒後に発効します。
この動作を制御する設定項目は以下のとおりです。
dom.min_tracking_timeout_value
: 4dom.min_tracking_background_timeout_value
: 10000dom.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 で呼び出したとしても、直ちに実行するのではなくキューに載せて、次の機会に実行するようスケジューリングされるためです。現在実行中のコードはキューにある関数を実行する前に完了しなければならず、このために実行結果の順序が想定どおりにならない場合があります。
WebExtension のバックグラウンドページでは、タイマーが正しく動作しません。これはバックグラウンドページが実際には常にロードされたままではないからです。ブラウザ-は使用されていない場合はアンロードし、必要なときに復元することができます。これは拡張機能にはほとんど透過的ですが、いくつかのもの (JS タイマーを含む) はアンロード/リストアサイクル全体では動作しないので、バックグラウンドページは代わりにアラームを使うことを推奨します。これについての詳細は Migrate to Event Driven Background Scripts にあります。
この記事の執筆時点では、 Chrome だけが上記の挙動を示していました - Firefox はまだアンロード/リストアの挙動をしていないので、タイマーは動作するでしょう。しかし、いくつかの理由から WebExtensions でタイマーを使わないようにするのはまだ良い考えです。
Internet Explorer、Chrome、Safari、Firefox を含むブラウザーは、内部で遅延時間を 32 ビット符号付き整数値で保存します。このため 2,147,483,647 ms (約 24.8 日) より大きな遅延時間を使用すると整数値がオーバーフローして、その結果直ちに実行されるタイムアウトになります。
仕様書 | 状態 | 備考 |
---|---|---|
{{SpecName('HTML WHATWG', 'webappapis.html#dom-settimeout', 'WindowOrWorkerGlobalScope.setTimeout()')}} | {{Spec2("HTML WHATWG")}} | 最新の仕様で、メソッドを WindowOrWorkerGlobalScope ミックスインに移動。 |
{{SpecName("HTML WHATWG", "webappapis.html#dom-settimeout", "WindowTimers.setTimeout()")}} | {{Spec2("HTML WHATWG")}} | 初回定義 (DOM Level 0) |
{{Compat("api.WindowOrWorkerGlobalScope.setTimeout")}}