1. 8.6 タイマー
    2. 8.7 マイクロタスクのキュー
    3. 8.8 ユーザープロンプト
      1. 8.8.1 単純ダイアログ
      2. 8.8.2 印刷

8.6 タイマー

setTimeout()setInterval()メソッドは、著者がタイマーベースのコールバックをスケジュールできるようにする。

id = self.setTimeout(handler [, timeout [, ...arguments ] ])

setTimeout

Support in all current engines.

Firefox1+Safari1+Chrome1+
Opera4+Edge79+
Edge (Legacy)12+Internet Explorer4+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android10.1+

timeoutミリ秒後にhandlerを実行するためにタイムアウトをスケジュールする。すべてのargumentsは直接handlerに渡される。

id = self.setTimeout(code [, timeout ])

timeoutミリ秒後にcodeを実行するためにタイムアウトをスケジュールする。

self.clearTimeout(id)

clearTimeout

Support in all current engines.

Firefox1+Safari4+Chrome1+
Opera4+Edge79+
Edge (Legacy)12+Internet Explorer4+
Firefox Android?Safari iOS1+Chrome Android?WebView Android37+Samsung Internet?Opera Android10.1+

idで識別されるsetTimeout()またはsetInterval()で設定されたタイムアウトをキャンセルする。

id = self.setInterval(handler [, timeout [, ...arguments ] ])

setInterval

Support in all current engines.

Firefox1+Safari1+Chrome1+
Opera4+Edge79+
Edge (Legacy)12+Internet Explorer4+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android10.1+

timeoutミリ秒ごとにhandlerを実行するためにタイムアウトをスケジュールする。すべてのargumentsは直接handlerに渡される。

id = self.setInterval(code [, timeout ])

timeoutミリ秒ごとにcodeを実行するためにタイムアウトをスケジュールする。

self.clearInterval(id)

clearInterval

Support in all current engines.

Firefox1+Safari1+Chrome1+
Opera4+Edge79+
Edge (Legacy)12+Internet Explorer4+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+Samsung Internet?Opera Android10.1+

idで識別されるsetInterval()またはsetTimeout()で設定されたタイムアウトをキャンセルする。

タイマーは入れ子にすることができる。しかし、5つのそのようなネストされたタイマー後に、間隔は少なくとも4ミリ秒であることが強制される。

このAPIは、タイマーがスケジュールどおり正確に動作することを保証しない。CPU負荷やその他のタスクなどによる遅延が予想される。

Objects that implement the WindowOrWorkerGlobalScope mixin have a map of active timers, which is a map, initially empty. Each key in this map is an identifier for a timer, and each value is a DOMHighResTimeStamp, representing the expiry time for that timer.

For entries put in the map of active timers by the timer initialization steps, i.e., by setTimeout() and setInterval(), the keys are numbers. For other specifications that use the run steps after a timeout algorithm, the identifier is a unique non-numeric value. Only the numeric-keyed timers are affected by clearTimeout() and clearInterval(), but all timers contribute to idle deadline computation, and are cleared when the relevant global is destroyed.


The setTimeout(handler, timeout, ...arguments) method steps are to return the result of running the timer initialization steps given this, handler, timeout, arguments, and false.

The setInterval(handler, timeout, ...arguments) method steps are to return the result of running the timer initialization steps given this, handler, timeout, arguments, and true.

The clearTimeout(id) and clearInterval(id) method steps are to remove this's map of active timers[id].

Because clearTimeout() and clearInterval() clear entries from the same map, either method can be used to clear timers created by setTimeout() or setInterval().


The timer initialization steps, given a WindowOrWorkerGlobalScope global, a string or Function handler, a number timeout, a list arguments, a boolean repeat, and optionally (and only if repeat is true) a number previousId, are:

  1. Let thisArg be global if that is a WorkerGlobalScope object; otherwise let thisArg be the WindowProxy that corresponds to global.

  2. If previousId was given, let id be previousId; otherwise, let id be an implementation-defined integer that is greater than zero and does not already exist in global's map of active timers.

  3. If the surrounding agent's event loop's currently running task is a task that was created by this algorithm, then let nesting level be the task's timer nesting level. Otherwise, let nesting level be zero.

    The task's timer nesting level is used both for nested calls to setTimeout(), and for the repeating timers created by setInterval(). (Or, indeed, for any combination of the two.) In other words, it represents nested invocations of this algorithm, not of a particular method.

  4. If timeout is less than 0, then set timeout to 0.

  5. If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.

  6. Let realm be global's relevant realm.

  7. Let initiating script be the active script.

  8. Assert: initiating script is not null, since this algorithm is always called from some script.

  9. Let task be a task that runs the following substeps:

    1. If id does not exist in global's map of active timers, then abort these steps.

    2. If handler is a Function, then invoke handler given arguments with the callback this value set to thisArg. If this throws an exception, catch it, and report the exception.

    3. Otherwise:

      1. Assert: handler is a string.

      2. Perform HostEnsureCanCompileStrings(realm). If this throws an exception, catch it, report the exception, and abort these steps.

      3. Let settings object be global's relevant settings object.

      4. Let base URL be initiating script's base URL.

      5. Assert: base URL is not null, as initiating script is a classic script or a JavaScript module script.

      6. Let fetch options be a script fetch options whose cryptographic nonce is initiating script's fetch options's cryptographic nonce, integrity metadata is the empty string, parser metadata is "not-parser-inserted", credentials mode is initiating script's fetch options's credentials mode, and referrer policy is initiating script's fetch options's referrer policy.

        The effect of these options ensures that the string compilation done by setTimeout() and setInterval() behaves equivalently to that done by eval(). That is, module script fetches via import() will behave the same in both contexts.

      7. Let script be the result of creating a classic script given handler, settings object, base URL, and fetch options.

      8. Run the classic script script.

    4. If id does not exist in global's map of active timers, then abort these steps.

      It might have been removed via the author code in handler calling clearTimeout() or clearInterval().

    5. If repeat is true, then perform the timer initialization steps again, given global, handler, timeout, arguments, true, and id.

    6. Otherwise, remove global's map of active timers[id].

  10. Increment nesting level by one.

  11. Set task's timer nesting level to nesting level.

  12. Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task.

  13. Run steps after a timeout given global, "setTimeout/setInterval", timeout, completionStep, and id.

  14. Return id.

Argument conversion as defined by Web IDL (for example, invoking toString() methods on objects passed as the first argument) happens in the algorithms defined in Web IDL, before this algorithm is invoked.

So for example, the following rather silly code will result in the log containing "ONE TWO ":

var log = '';
function logger(s) { log += s + ' '; }

setTimeout({ toString: function () {
  setTimeout("logger('ONE')", 100);
  return "logger('TWO')";
} }, 100);

遅延なく背中合わせに数ミリ秒のタスクを実行するために、飢えたユーザーインターフェイスを避けるために(およびCPUを占有するためのスクリプトを殺すブラウザーを避けるために)ブラウザーに戻って従いつつ、作業を実行する前の簡単なキューの次のタイマー:

function doExpensiveWork() {
  var done = false;
  // ...
  // this part of the function takes up to five milliseconds
  // set done to true if we're done
  // ...
  return done;
}

function rescheduleWork() {
  var id = setTimeout(rescheduleWork, 0); // preschedule next iteration
  if (doExpensiveWork())
    clearTimeout(id); // clear the timeout if we don't need it
}

function scheduleWork() {
  setTimeout(rescheduleWork, 0);
}

scheduleWork(); // queues a task to do lots of work

To run steps after a timeout, given a WindowOrWorkerGlobalScope global, a string orderingIdentifier, a number milliseconds, a set of steps completionSteps, and an optional value timerKey:

  1. Assert: if timerKey is given, then the caller of this algorithm is the timer initialization steps. (Other specifications must not pass timerKey.)

  2. If timerKey is not given, then set it to a new unique non-numeric value.

  3. Let startTime be the current high resolution time given global.

  4. Set global's map of active timers[timerKey] to startTime plus milliseconds.

  5. Run the following steps in parallel:

    1. If global is a Window object, wait until global's associated Document has been fully active for a further milliseconds milliseconds (not necessarily consecutively).

      Otherwise, global is a WorkerGlobalScope object; wait until milliseconds milliseconds have passed with the worker not suspended (not necessarily consecutively).

    2. Wait until any invocations of this algorithm that had the same global and orderingIdentifier, that started before this one, and whose milliseconds is equal to or less than this one's, have completed.

    3. Optionally, wait a further implementation-defined length of time.

      This is intended to allow user agents to pad timeouts as needed to optimize the power usage of the device. For example, some processors have a low-power mode where the granularity of timers is reduced; on such platforms, user agents can slow timers down to fit this schedule instead of requiring the processor to use the more accurate mode with its associated higher power usage.

    4. Perform completionSteps.

    5. If timerKey is a non-numeric value, remove global's map of active timers[timerKey].

Run steps after a timeout is meant to be used by other specifications that want to execute developer-supplied code after a developer-supplied timeout, in a similar manner to setTimeout(). (Note, however, it does not have the nesting and clamping behavior of setTimeout().) Such specifications can choose an orderingIdentifier to ensure ordering within their specification's timeouts, while not constraining ordering with respect to other specification's timeouts.

8.7 マイクロタスクのキュー

queueMicrotask

Support in all current engines.

Firefox69+Safari12.1+Chrome71+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
self.queueMicrotask(callback)

指定されたcallbackを実行するためのマイクロタスクキューに入れる

queueMicrotask(callback)メソッドは、callback呼び出すためにマイクロタスクをキューに入れ、かつcallbackが例外を投げた場合は例外を報告しなければならない。

queueMicrotask()メソッドは、著者がマイクロタスクキューでコールバックをスケジュールすることを可能にする。これは、JavaScript実行コンテキストスタックが次に空になるとコードを実行でき、これは、現在実行中のすべての同期JavaScriptが完了するまで実行されたときに発生する。これは、たとえばsetTimeout(f, 0)を使用する場合のように、イベントループに制御を戻すことはない。

著者は、大量のマイクロタスクをスケジュールすることが、大量の同期コードを実行するのと同じパフォーマンスの低下があることに注意する必要がある。 どちらも、ブラウザーがレンダリングなどの独自の作業を実行を妨げることになる。多くの場合、requestAnimationFrame()またはrequestIdleCallback()の方がよい選択である。 特に、次のレンダリングサイクルの前にコードを実行することが目標である場合、それはrequestAnimationFrame()の目的である。

次の例からわかるように、queueMicrotask()について考える最良の方法は、同期コードを再配置するためのメカニズムとして、現在実行中の同期JavaScriptが完了した直後にキューに入れられたコードを効果的に配置することである。

queueMicrotask() 使用する最も一般的な理由は、情報が同期的に利用できる場合でも、過度の遅延を発生させることなく、一貫した順序を作成することである。

たとえば、以前にロードされたデータの内部キャッシュも維持する、loadイベントを発生させるカスタム要素について考えてみる。ナイーブな実装は次のようになるだろう:

MyElement.prototype.loadData = function (url) {
  if (this._cache[url]) {
    this._setData(this._cache[url]);
    this.dispatchEvent(new Event("load"));
  } else {
    fetch(url).then(res => res.arrayBuffer()).then(data => {
      this._cache[url] = data;
      this._setData(data);
      this.dispatchEvent(new Event("load"));
    });
  }
};

しかし、このナイーブな実装には、ユーザーに一貫性のない動作が発生するという問題がある。たとえば、次のようなコードは

element.addEventListener("load", () => console.log("loaded"));
console.log("1");
element.loadData();
console.log("2");

"1, 2, loaded"(データをフェッチする必要がある場合)を記録することもあれば、"1, loaded, 2"(データがすでにキャッシュされている場合)を記録することもある。同様に、loadData()の呼び出し後、データが要素に設定されているかどうかは一貫性がない。

一貫した順序を取得するためには、queueMicrotask()を使用できる:

MyElement.prototype.loadData = function (url) {
  if (this._cache[url]) {
    queueMicrotask(() => {
      this._setData(this._cache[url]);
      this.dispatchEvent(new Event("load"));
    });
  } else {
    fetch(url).then(res => res.arrayBuffer()).then(data => {
      this._cache[url] = data;
      this._setData(data);
      this.dispatchEvent(new Event("load"));
    });
  }
};

キューに入れられたコードをJavaScript実行コンテキストスタックが空になった後になるように基本的に再配置することで、要素の状態の一貫した順序付けおよび更新が保証される。

queueMicrotask()のもう1つの興味深い使用法は、 複数の呼び出し元による作業の調整されていない"バッチ処理"を可能にすることである。たとえば、できるだけ早くどこかにデータを送信したいが、簡単に回避できる場合は、 複数のネットワークリクエストを行いたくないライブラリ関数について考えてみる。このバランスをとる1つの方法は次のようになる:

const queuedToSend = [];

function sendData(data) {
  queuedToSend.push(data);

  if (queuedToSend.length === 1) {
    queueMicrotask(() => {
      const stringToSend = JSON.stringify(queuedToSend);
      queuedToSend.length = 0;

      fetch("/endpoint", stringToSend);
    });
  }
}

このアーキテクチャでは、現在実行中の同期JavaScript内でsendData()を呼び出す複数の後続の呼び出しは、1つのfetch()呼び出しにまとめられるが、イベントループのタスクがフェッチを先取りすることはない(代わりに同様のコードで発生した場合のようにsetTimeout()を使用する)。

8.8 ユーザープロンプト

8.8.1 単純ダイアログ

window.alert(message)

Window/alert

Support in all current engines.

Firefox1+Safari1+Chrome1+
Opera3+Edge79+
Edge (Legacy)12+Internet Explorer4+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android10.1+

指定されたメッセージを持つモーダルアラートを表示し、それを命令するユーザーに対して待機する。

result = window.confirm(message)

Window/confirm

Support in all current engines.

Firefox1+Safari1+Chrome1+
Opera3+Edge79+
Edge (Legacy)12+Internet Explorer4+
Firefox Android?Safari iOS?Chrome Android?WebView Android1+Samsung Internet?Opera Android10.1+

与えられたメッセージとともにモーダルOK/Cancelプロンプトを表示し、それを命令するユーザーに対して待機し、ユーザーがOKをクリックした場合はtrueを返し、ユーザーがCancelをクリックする場合はfalseを返す。

result = window.prompt(message [, default])

Window/prompt

Support in all current engines.

Firefox1+Safari1+Chrome1+
Opera3+Edge79+
Edge (Legacy)12+Internet Explorer4+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android10.1+

与えられたメッセージとともにモーダルテキストコントロールプロンプトを表示し、ユーザーがそれを閉じるのを待ち、ユーザーが入力した値を返す。ユーザーがプロンプトをキャンセルした場合、代わりにnullを返す。2番目の引数が存在する場合、指定された値がデフォルトとして使用される。

メディアデータを読み込むメディア要素のような、タスクまたはマイクロタスクに依存するロジックは、このメソッドが発動されるときに延期される。

The alert() and alert(message) method steps are:

  1. If we cannot show simple dialogs for this, then return.

  2. If the method was invoked with no arguments, then let message be the empty string; otherwise, let message be the method's first argument.

  3. Set message to the result of normalizing newlines given message.

  4. Set message to the result of optionally truncating message.

  5. Show message to the user, treating U+000A LF as a line break.

  6. Invoke WebDriver BiDi user prompt opened with this, "alert", and message.

  7. Optionally, pause while waiting for the user to acknowledge the message.

  8. Invoke WebDriver BiDi user prompt closed with this and true.

This method is defined using two overloads, instead of using an optional argument, for historical reasons. The practical impact of this is that alert(undefined) is treated as alert("undefined"), but alert() is treated as alert("").

The confirm(message) method steps are:

  1. If we cannot show simple dialogs for this, then return false.

  2. Set message to the result of normalizing newlines given message.

  3. Set message to the result of optionally truncating message.

  4. Show message to the user, treating U+000A LF as a line break, and ask the user to respond with a positive or negative response.

  5. Invoke WebDriver BiDi user prompt opened with this, "confirm", and message.

  6. Pause until the user responds either positively or negatively.

  7. Invoke WebDriver BiDi user prompt closed with this, and true if the user responded positively or false otherwise.

  8. If the user responded positively, return true; otherwise, the user responded negatively: return false.

The prompt(message, default) method steps are:

  1. If we cannot show simple dialogs for this, then return null.

  2. Set message to the result of normalizing newlines given message.

  3. Set message to the result of optionally truncating message.

  4. Set default to the result of optionally truncating default.

  5. Show message to the user, treating U+000A LF as a line break, and ask the user to either respond with a string value or abort. The response must be defaulted to the value given by default.

  6. Invoke WebDriver BiDi user prompt opened with this, "prompt" and message.

  7. Pause while waiting for the user's response.

  8. Let result be null if the user aborts, or otherwise the string that the user responded with.

  9. Invoke WebDriver BiDi user prompt closed with this, false if result is null or true otherwise, and result.

  10. Return result.

To optionally truncate a simple dialog string s, return either s itself or some string derived from s that is shorter. User agents should not provide UI for displaying the elided portion of s, as this makes it too easy for abusers to create dialogs of the form "Important security alert! Click 'Show More' for full details!".

For example, a user agent might want to only display the first 100 characters of a message. Or, a user agent might replace the middle of the string with "…". These types of modifications can be useful in limiting the abuse potential of unnaturally large, trustworthy-looking system dialogs.

We cannot show simple dialogs for a Window window when the following algorithm returns true:

  1. If the active sandboxing flag set of window's associated Document has the sandboxed modals flag set, then return true.

  2. If window's relevant settings object's origin and window's relevant settings object's top-level origin are not same origin-domain, then return true.

  3. If window's relevant agent's event loop's termination nesting level is nonzero, then optionally return true.
  4. Optionally, return true. (For example, the user agent might give the user the option to ignore all modal dialogs, and would thus abort at this step whenever the method was invoked.)

  5. falseを返す。

8.8.2 印刷

Window/print

Support in all current engines.

Firefox1+Safari1.1+Chrome1+
Opera6+Edge79+
Edge (Legacy)12+Internet Explorer5+
Firefox AndroidNoSafari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android10.1+
window.print()

ページを印刷するようユーザーに指示する。

The print() method steps are:

  1. Let document be this's associated Document.

  2. If document is not fully active, then return.

  3. If document's unload counter is greater than 0, then return.

  4. If document is ready for post-load tasks, then run the printing steps for document.

  5. Otherwise, set document's print when loaded flag.

User agents should also run the printing steps whenever the user asks for the opportunity to obtain a physical form (e.g. printed copy), or the representation of a physical form (e.g. PDF copy), of a document.

The printing steps for a Document document are:

  1. The user agent may display a message to the user or return (or both).

    For instance, a kiosk browser could silently ignore any invocations of the print() method.

    For instance, a browser on a mobile device could detect that there are no printers in the vicinity and display a message saying so before continuing to offer a "save to PDF" option.

  2. If the active sandboxing flag set of document has the sandboxed modals flag set, then return.

    If the printing dialog is blocked by a Document's sandbox, then neither the beforeprint nor afterprint events will be fired.

  3. The user agent must fire an event named beforeprint at the relevant global object of document, as well as any child navigable in it.

    Firing in children only doesn't seem right here, and some tasks likely need to be queued. See issue #5096.

    The beforeprint event can be used to annotate the printed copy, for instance adding the time at which the document was printed.

  4. The user agent should offer the user the opportunity to obtain a physical form (or the representation of a physical form) of document. The user agent may wait for the user to either accept or decline before returning; if so, the user agent must pause while the method is waiting. Even if the user agent doesn't wait at this point, the user agent must use the state of the relevant documents as they are at this point in the algorithm if and when it eventually creates the alternate form.

  5. The user agent must fire an event named afterprint at the relevant global object of document, as well as any child navigables in it.

    Firing in children only doesn't seem right here, and some tasks likely need to be queued. See issue #5096.

    The afterprint event can be used to revert annotations added in the earlier event, as well as showing post-printing UI. For instance, if a page is walking the user through the steps of applying for a home loan, the script could automatically advance to the next step after having printed a form or other.