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

8.6 タイマー

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

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

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

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

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

self.clearTimeout(handle)

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

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

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

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

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

self.clearInterval(handle)

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

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

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

遅延なく背中合わせに数ミリ秒のタスクを実行するために、飢えたユーザーインターフェイスを避けるために(および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 handle = setTimeout(rescheduleWork, 0); // preschedule next iteration
  if (doExpensiveWork())
    clearTimeout(handle); // clear the timeout if we don't need it
}

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

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

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

queueMicrotask

Support in all current engines.

Firefox69+Safari12.1+Chrome71+
Opera58+Edge79+
Edge (Legacy)NoInternet ExplorerNo
Firefox Android79+Safari iOS12.2+Chrome Android71+WebView Android71+Samsung Internet10.0+Opera Android50+
self.queueMicrotask(callback)

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

queueMicrotask()メソッドは、著者がマイクロタスクキューでコールバックをスケジュールすることを可能にする。This allows their code to run once the JavaScript execution context stack is next empty, which happens once all currently executing synchronous JavaScript has run to completion. This doesn't yield control back to the event loop, as would be the case when using, for example, setTimeout(f, 0).

著者は、大量のマイクロタスクをスケジュールすることが、大量の同期コードを実行するのと同じパフォーマンスの低下があることに注意する必要がある。 Both will prevent the browser from doing its own work, such as rendering. 多くの場合、requestAnimationFrame()またはrequestIdleCallback()の方がよい選択である。 特に、次のレンダリングサイクルの前にコードを実行することが目標である場合、それはrequestAnimationFrame()の目的である。

As can be seen from the following examples, the best way of thinking about queueMicrotask() is as a mechanism for rearranging synchronous code, effectively placing the queued code immediately after the currently executing synchronous JavaScript has run to completion.

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"));
    });
  }
};

By essentially rearranging the queued code to be after the JavaScript execution context stack empties, this ensures a consistent ordering and update of the element's state.

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);
    });
  }
}

With this architecture, multiple subsequent calls to sendData() within the currently executing synchronous JavaScript will be batched together into one fetch() call, but with no intervening event loop tasks preempting the fetch (as would have happened with similar code that instead used setTimeout()).

8.8 ユーザープロンプト

8.8.1 単純ダイアログ

window.alert(message)

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

result = window.confirm(message)

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

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

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

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

8.8.2 印刷

Window/print

Support in all current engines.

Firefox1+Safari1.1+Chrome1+
Opera6+Edge79+
Edge (Legacy)12+Internet Explorer5+
Firefox AndroidNoSafari iOS1+Chrome Android18+WebView Android1+Samsung Internet1.0+Opera Android10.1+
window.print()

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