CARVIEW |
このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。
起動パフォーマンスの最適化
起動パフォーマンスの向上は、多くの場合、実施可能なパフォーマンス最適化の中で最も価値の高いものの一つです。アプリの起動にはどれくらいの時間がかかりますか?アプリの読み込み中に端末やユーザーのブラウザーがフリーズしているように見えていませんか?それはユーザーにアプリケーションがクラッシュしたり、何か問題が起きているのではないかと不安を抱かせます。使い勝手を良くするためには、アプリがすばやく読み込まれるようにすることが必要です。この記事では、新規アプリケーションの作成と、その他のプラットフォームからウェブへのアプリケーション移植の両方について、パフォーマンスに関するヒントと提案を提供します。
高速非同期読み込み
プラットフォームに関わらず、起動は常にできるだけすばやく行うことがよい考えです。これは普遍的な課題であるため、ここではあまり深く掘り下げません。代わりに、ウェブアプリを構築する際に重要な課題である、起動をできるだけ非同期に行うことについて見ていきましょう。これは、起動時のコードをすべてアプリのメインスレッド上の単一のイベントハンドラーで実行しないということです。
むしろ、可能な限りバックグラウンドスレッドで処理を行うウェブワーカーを作成しましょう(例えば、データの取得や処理など)。タスクをウェブワーカーに委ねることで、メインスレッドはユーザーイベントや UI のレンダリングなど、メインスレッドが要求されるタスクに集中できるようになります。一方、メインスレッドのイベントは、大規模で時間のかかるタスクではなく、多くの小さなタスク(マイクロタスクとも呼ばれる)で構成されるべきです。
非同期読み込みは、ページやユーザーインターフェースが応答不能であるかのように現れる(または実際に応答不能になる)のを防ぎます。個々の読み込みタスクに必要な時間を最小限に抑えることで、アプリケーションのイベントループは起動中に循環を続けるのです。これにより、アプリケーション、ブラウザー、端末がフリーズしたようになるのを防ぎます。
最悪の場合、メインスレッドをブロックすると、ユーザーがアプリをアンインストールする事態が発生する可能性があります。例えば、誤ってアプリを起動したユーザーがアプリケーションを閉じられない場合、誤操作を繰り返さないよう措置を講じたいと思うかもしれません。
意思があるところに…
最初からすべてを「適切な方法」で記述する方が、後からパフォーマンス(およびアクセシビリティ)のために改修するよりも容易です。 ゼロから始める場合、適切なコード部分を非同期化すれば、後付けの改修は不要になります。純粋な起動時の計算はすべてバックグラウンドスレッドで実行し、メインスレッドのイベント実行時間を可能な限り短く保つべきです。ユーザーに進行状況や待ち時間を示すための進捗インジケーターを記述する代わりに、進捗バー自体を不要にしましょう。
一方、既存アプリをウェブへ移植するのは困難な場合があります。ネイティブアプリケーションは非同期方式で記述する必要がありません。通常、オペレーティングシステムが読み込み処理を代行するからです。元のアプリケーションにはメインループがある場合が多くの場合で、これを非同期動作(それぞれのループ反復を別個の形で実行)に容易に変更できます。起動処理は単一の連続した手順であることが多く、進捗メーターを定期的に更新する程度です。
ウェブワーカーを使用することで、非常に大規模で長時間実行される JavaScript コードの塊を非同期で実行することができますが、重大な注意点があります。ウェブワーカーは DOM を直接操作できず、 window オブジェクトのメソッドやプロパティへのアクセスも制限されており、 WebGL へのアクセスは一切できません。つまり、起動プロセス内の「純粋な計算処理」の塊を簡単にワーカーに移行できない限り、起動コードの大部分またはすべてをメインスレッド上で実行するほかない、ということです。
ただし、そのように見えるコードでも、少しの手間で非同期にすることができます。
非同期にする
起動プロセスが可能な限り非同期であるようにする方法(新しいアプリでも移植でも)のいくつかの提案を、以下を示します。
defer
またはasync
属性を、ウェブアプリケーションで必要な script タグに付与します。これにより、 HTML パーサーはスクリプトのダウンロードと実行が完了するまで待たずに、文書の処理を続けることができます。- 資産ファイルのデコードが必要な場合(例えば、JPEGファイルをデコードしてWebGLで後で使用される生のテクスチャデータに変換する場合)、ワーカーでデコードするのが最適です。
- ブラウザーの対応しているデータ(例えば、画像データのデコードする)を扱う際は、自分自身で実装したデコーダーや元のコードベースのデコーダーを使用せず、ブラウザーや端末に組み込まれたデコーダーを利用してください。 提供されたデコーダーはほぼ確実に大幅に高速であり、さらにアプリのサイズも縮小できます。加えて、ブラウザーはこれらのデコーダーを自動的に並列処理する可能性があります。
- 並列にできるデータ処理はすべて並列に行うのが最適です。データをひとつひとつ順番に処理するのではなく、可能な限りまとめて処理しましょう。
- 起動用 HTML ファイルには、クリティカルレンダリングパスに関与しないスクリプトやスタイルシートを含めないでください。必要な時だけ読み込むようにしてください。
- JavaScript ファイルのサイズを縮小してください。ブラウザーにはミニファイ版を送信し、Gzip や Brotli などの圧縮技術を使用するようにしてください。
- できる限りリソースヒント(preconnect や preload など)を活用し、アプリケーションにとってより重要なファイルをブラウザーに示してください。
非同期でできる作業が多ければ多いほど、アプリはマルチコアプロセッサーの利点を、より効果的に引き出すことができます。
移植の課題
初期読み込みが済んだ後、アプリのメインコードの実行が始まると、特に移植版の場合、アプリがシングルスレッドである必要がある場合ができます。メインコードの起動プロセスを支援するために最も重要なのは、コードを小さな部分にリファクタリングするのが最適であることです。これらの部分は、アプリのメインループへの複数回の呼び出しの間に分散して実行できる(これによりメインスレッドが入力処理などを行える)ようにします。
Emscripten はこのリファクタリングを支援する API を提供します。例えば、 emscripten_push_main_loop_blocker()
を使用することができます。これにより、メインスレッドが続けることを許可される前に実行される関数を設定できます。順次呼び出される関数のキューを設定することで、メインスレッドをブロックせずに実行中のコード断片をより容易に管理できます。
ただし、既存のコードを実際にその方法で動作するようリファクタリングする必要があるという問題が残ります。それには時間がかかる可能性があります。
どの程度非同期にすればよいのか
サイトが最初に使用可能になるまでの時間が短く、ユーザー入力へのレスポンスが速いほど、そのサイトはより良く評価されます。 コンテンツが最初に現れるまでに 1 ~ 2 秒かかるサイトは通常、高速と認識されます。 3 ~ 4 秒かかるサイトに慣れている場合、 7 ~ 8 秒はとても長く感じられるでしょう。
レスポンスに関して言えば、ユーザーは 50 ミリ秒以下の遅延には気づきません。 200 ミリ秒を超える遅延があると、ユーザーはサイトを重く感じるでしょう。アプリケーションの読み込み速度やレスポンスを改善する際には、多くのユーザーがあなたよりも古く遅いコンピューターを保有している可能性があるため、あなたよりも長い遅延を経験するかもしれないことを忘れないでください。
その他の提案
非同期化する以外にも、アプリの起動時間を改善するのに役立つことがいくつかあります。以下にその一部を紹介します。
- ダウンロード時間
-
ユーザーがアプリケーションのデータをダウンロードするまでに要する時間を考慮してください。アプリケーションがとても人気が非常に高い場合や、コンテンツを頻繁に再ダウンロードする必要がある場合は、可能な限り高速なホストサーバーを用意すべきです。常にデータを圧縮し、可能な限り小さくしてください。
- データサイズ
-
データのサイズを最適化するようするのが最適です。小さな容量のファイルほど、ダウンロードする速度や処理において、より大きなファイルよりも速く、かつ速やかに処理されるのです。
- 主観的要因
-
起動プロセス中にユーザーの関心を維持するための何らかの工夫は、時間の経過を早く感じさせるのに役立つ。偽のスプラッシュ画面を表示することでも、知覚的パフォーマンスを改善することができます。負荷の大きいサイトでは、アプリが何もしていないように見える状態を避け、何か処理を行っているとユーザーに感じさせる工夫が効果的です。