isInputPending() を使用した JS スケジューリングの改善

新しい JavaScript API を使用すると、読み込みパフォーマンスと入力応答性のトレードオフを回避できます。

Nate Schloss
Nate Schloss
Andrew Comminos
Andrew Comminos

読み込みを速くするのは簡単ではありません。現在 JS を利用してコンテンツをレンダリングしているサイト 負荷のパフォーマンスと入力のトレードオフを ディスプレイに必要なすべての作業を行うか、 (読み込みパフォーマンスの向上、入力応答性の低下)、または さまざまなタスクへの応答性を維持するために、作業を小さなタスクに分割する 入力とペイント(負荷パフォーマンスが悪く、入力が優れています) 対応しています)。

このトレードオフをなくすために、Facebook はこれを提案して実装しました。 Chromium の isInputPending() API を使用して、応答性を向上させます。 減ります。オリジン トライアルのフィードバックに基づいて、 API でしたが、このたび、Chromium で API がデフォルトでリリースされるようになったことをお知らせいたします。 87!

ブラウザの互換性

対応ブラウザ

  • Chrome: 87。 <ph type="x-smartling-placeholder">
  • Edge: 87。 <ph type="x-smartling-placeholder">
  • Firefox: サポートされていません。 <ph type="x-smartling-placeholder">
  • Safari: サポートされていません。 <ph type="x-smartling-placeholder">

ソース

バージョン 87 以降、isInputPending() は Chromium ベースのブラウザに搭載されています。 どのブラウザでも、この API を配布する意思は示されていません。

背景

今日の JS エコシステムにおける作業のほとんどは、メインスレッドという 1 つのスレッドで行われます。 デベロッパーには堅牢な実行モデルが提供されますが、ユーザー エクスペリエンスは (特に応答性)スクリプトが長時間実行されると、著しく低下する あります。入力イベントの発生中にページで大量の処理が行われている場合は たとえばクリック入力イベントの処理は その処理が完了するまで行われません 表示されます。

現時点では、この問題への対処として、 JavaScript を小さなブロックに分割します。ページの読み込み中、そのページでは ブラウザに制御を戻します。「 ブラウザは入力イベント キューをチェックして、 説明する必要がありますその後、ブラウザは 追加された JavaScript ブロックです。この方法は役立ちますが、他の問題を引き起こす可能性があります。

ページからブラウザに制御が戻るたびに、 入力イベントキューをチェックしてイベントを処理し、 JavaScript ブロック。ブラウザはより迅速にイベントに応答しますが、 ページの読み込みが遅くなりますあまりに頻繁に発生すると 。発生頻度が下がるとブラウザが 反応が悪くなり 人々は不満を抱きます面白くない。

長い JS タスクを実行すると、ブラウザがイベントをディスパッチする時間が減ることを示す図。

Facebook では、新しいアイデアを思いつき、 新しい読み込み方法を採用することで こうしたストレスの軽減を図りました水 これについて Chrome の担当者に 問い合わせて提案を導き出しました isInputPending()isInputPending() API は、 ウェブでのユーザー入力を中断し、JavaScript を ブラウザを経由せずに入力を確認できます。

isInputPending() を使用することで、実行をブラウザに完全に戻すことなく、JS が保留中のユーザー入力があるかどうかを確認できることを示す図。

API に関心が寄せられたため、Chrome の同僚と協力しています。 Chromium に機能を実装してリリースできます。Chrome を活用 オリジン トライアルでパッチを公開した (Chrome で変更をテストして、デベロッパーからフィードバックを得る方法) API を完全にリリースする前に)。

オリジン トライアルと他のメンバーからのフィードバックを参考に、 W3C Web Performance Working Group に参加し、API の変更を実装しました。

例: yiey スケジューラ

アプリケーションを読み込むためにディスプレイ ブロッキング処理を多数行っているとします。 たとえば、コンポーネントからのマークアップの生成、素数の計算、 読み込みスピナーを描画しますそれぞれが個別のテーブルに分割され、 作業アイテムを表します。スケジューラ パターンを使用して、 架空の processWorkQueue() 関数で行う作業は次のようになります。

const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
  if (performance.now() >= DEADLINE) {
    // Yield the event loop if we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

後で新しいマクロタスクで setTimeout() を介して processWorkQueue() を呼び出すと、次のようになります。 ブラウザが入力に対してある程度の応答性を維持できるようにします( 処理の再開前にイベント ハンドラを実行すること)を比較的簡単に行うことができ、 できます。ただし、他の業務により長時間、スケジュールが解除される可能性はあります。 イベントループの制御が必要な場合や、最大 QUANTUM ミリ秒まで延長が必要な場合 イベントレイテンシの短縮につながります

どうでしょうか?正解です。

const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
  if (navigator.scheduling.isInputPending() || performance.now() >= DEADLINE) {
    // Yield if we have to handle an input event, or we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

navigator.scheduling.isInputPending() への呼び出しを導入することで、以下のことが可能になります。 ディスプレイ ブロック処理を損なわないようにしつつ、入力への応答を高速化 それ以外は中断なく実行されます処理する必要がない場合は 作業が完了するまで入力(ペイントなど)以外の場合、 QUANTUM の長さも考慮する必要があります。

デフォルトは「連続」です。イベントは isInputPending() から返されません。これらの mousemovepointermove などがあります。100%で利益を出したい場合は 作成することもできます次のようにして、isInputPending() にオブジェクトを提供する。 includeContinuoustrue に設定されたので、次の手順に進みます。

const DEADLINE = performance.now() + QUANTUM;
const options = { includeContinuous: true };
while (workQueue.length > 0) {
  if (navigator.scheduling.isInputPending(options) || performance.now() >= DEADLINE) {
    // Yield if we have to handle an input event (any of them!), or we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

これで、React などのフレームワークでは、isInputPending() サポートが コア スケジューリング ライブラリを使用できます。これがうまくいけば これらのフレームワークを使用して isInputPending() のメリットを得られるデベロッパー 大幅に削減されます

歩行性能は必ずしも悪いとは限らない

生産性を低下させることが すべてのユースケースに適したソリューションであるとは限りません あります。ブラウザに制御を戻す理由はさまざまですが、 入力イベントの処理(レンダリングの実行や、他のスクリプトの実行など)を 表示されます。

ブラウザで、保留状態を正しく関連付けできないことがあります。 作成できます。特に、クロスオリジン用の複雑なクリップやマスクの設定は、 iframe で偽陰性が報告されることがある(例: isInputPending() が予期せず false に設定します)。収益を増やすには サイトでスタイル化されたサブフレームを操作する必要がある場合

イベントループを共有する他のページにも注意してください。プラットフォーム 複数のオリジンでイベントを共有することは あります。入力がインスタンスにディスパッチされた場合、isInputPending()true を返しません。 背景のページが干渉し、 フォアグラウンド ページの応答性が向上します。予算を減らす、延期する、収益を増やすなどの Page Visibility API を使ってバックグラウンドで作業を行う場合に発生する頻度は高まります。

状況に応じて isInputPending() を使用することをおすすめします。コンバージョン トラッキングの ユーザー ブロッキング作業を完了してから、イベントループで他のユーザーに優しく より頻繁に生成されます時間のかかるタスクは有害となる可能性があります

フィードバック

  • 仕様に関するフィードバックは、 is-input-pending リポジトリ。
  • @acomminos(仕様作成者の一人)に連絡する 。

まとめ

isInputPending() がリリースされ、デベロッパーが すぐに使い始めることができますこの API は、Facebook が 新しいウェブ API を開発し、アイデアのインキュベーションから標準の提案、 確認できます。この道のりにたどり着いたすべての人に感謝します 私たちを成長させてくれた Chrome の皆さんに感謝を伝えます。 アイデアを形にして、配送する!

ヒーロー写真撮影: Will H McMahanスプラッシュを解除