ウェブアプリのパフォーマンスに関するベストプラクティス
ユーザーに好まれるアプリを構築するには、パフォーマンスに優れたアプリにすることが不可欠です。開発プロセス全体を通してパフォーマンスをモニタリングしてください。レイテンシを表す主な指標には、最初のフレームまでの時間(TTFF)と使用準備完了(RTU)の2つがあり、後者は描画完了までの時間(TTFD)とも呼ばれます。ここでは、アプリのパフォーマンスを向上させる一般的なベストプラクティスをいくつか取り上げます。

ネイティブのSplashScreen APIの使用
アプリの起動時のパフォーマンスは、ユーザーエクスペリエンスに影響を与えます。ユーザーは、アプリを起動時したらすぐに何らかの画面が表示されることを期待しています。その表示までの速さを表す指標が、TTFF(最初のフレームまでの時間)です。Vega ScriptのネイティブのSplashScreen機能は、画像アセットを使用してアプリ固有のスプラッシュ画面を表示する機能を提供します。これを使用すると、アプリの起動時にすぐにスプラッシュ画面がユーザーに表示されます。アプリでは、JavaScriptベースのスプラッシュスクリーンをレンダリングすることに時間を割く必要なく、コンテンツの読み込みとネットワーク呼び出しに集中できます。スプラッシュ画面には、一連のアニメーション画像によるアニメーション効果を含めることができます。
このKPIは、manifest.tomlファイル内のメインコンポーネントが起動されてから、最初のフレームが画面にレンダリングされるまでにかかる時間として計算されます。

SplashScreenManagerを使用すると、アプリの次の画面に進むまでの画面用に、静的グラフィックスまたはアニメーショングラフィックスを作成できます。SplashScreenアセットは、アプリをパッケージ化するときにバンドルされ、アプリの起動時にデバイスによって使用されます。SplashScreenにより、アプリ起動時の複雑な処理の一部が不要になり、アプリで最初のフレームを表示する準備ができたときに開発者が消去するまで、起動画面を表示しておくことができます。
TTFD(描画完了までの時間)マーカーの実装
Vegaアプリは、アプリライフサイクルの各段階で特定のパフォーマンスマーカーを報告することが期待されています。このようなマーカーの1つがTTFD(前の画像を参照)で、アプリが正常に読み込まれ、ユーザー操作に対応する準備ができたときにアプリから報告します。これは、クールスタート(アプリプロセスがまだ存在していない場合)とウォームスタート(アプリプロセスが既に存在する場合)に適用されます。ウェブアプリでは、ウェブアプリのコンテンツが完全に読み込まれたときに、onLoadコールバックでこのマーカーを実装する必要があります。
ウェブアプリが起動して読み込まれたら、useReportFullyDrawn()メソッドを呼び出します。ラッパーにはonLoadイベントがあり、アプリが起動して準備が整ったときにトリガーされます。また、ウォーム起動中にバックグラウンドからフォアグラウンドに移動したときも、reportFullyDrawn()メソッドを呼び出します。
次のサンプルコードでは、コールドスタート(onLoad)とウォームスタート(keplerAppState)の両方の処理でuseReportFullyDrawn()を呼び出しています。
import { useReportFullyDrawn } from '@amazon-devices/kepler-performance-api';
import React, { useEffect, useState, useRef } from 'react';
import {VegaAppStateChange, useAddVegaAppStateListenerCallback, useGetCurrentVegaAppStateCallback} from '@amazon-devices/react-native-kepler';
...
...
export const App = () => {
const reportFullyDrawnCallback = useReportFullyDrawn();
const getCurrentVegaAppStateCallback = useGetCurrentVegaAppStateCallback();
const addVegaAppStateListenerCallback = useAddVegaAppStateListenerCallback();
const [appState, setAppState] = useState(getCurrentVegaAppStateCallback);
// useEffectフックを使用して、最初のレンダリングの後、状態が
// フォアグラウンドに変わるときに、描画完了の報告が実行されるようにします。
// アプリで追加の非同期処理を実行していて、
// その処理が完了するまで描画完了にならない場合は、
// 処理の完了状態を依存関係の配列に渡し、フック内で
// 状態を確認します。
useEffect(() => {
const changeSubscription = addVegaAppStateListenerCallback(
'change',
handleAppStateChange
);
}, [reportFullyDrawnCallback]);
const handleAppStateChange = (nextAppState: any) => {
if (
appState.match(/inactive|background/) &&
nextAppState === 'active'
) {
reportFullyDrawnCallback();
}
setAppState(nextAppState);
};
...
...
return (
<View style={styles.sectionContainer}>
<WebView
.
.
.
onLoad={(event) => {
console.log("onLoad url: ", event.nativeEvent.url)
// スプラッシュ画面を非表示にしてコンテンツをレンダリングします。
SplashScreenManager.hideAsync(your.package.name).catch((e) => {
console.error("スプラッシュ画面を非表示にするときにエラーが発生しました:" , e) });
// 実際のページが読み込まれた場合にのみ描画完了を報告します。
if("https://mywebapp.com/home" === event.nativeEvent.url)
{
reportFullyDrawnCallback();
}
}}
/>
</View>
);
};
詳細については、How to implement reportFullyDrawn marker for Webview Appsを参照してください。
ネットワークリクエストの最適化
ウェブアプリの起動パフォーマンスを向上させるには、ネットワークリクエストを最適化する必要があります。その方法の1つは、HTTPリクエストを最小限に抑えることです。これには、可能な場合はCSSファイルとJavaScriptファイルを結合すること、スプライト画像を使用すること、外部のサードパーティへの依存関係の数を減らすことが効果的です。また、GzipやBrotliを使用してアセット圧縮を有効にすると、HTML、CSS、JavaScriptなどのテキストベースリソースのペイロードサイズを大幅に削減できます。ただし、画像ファイルは通常既に圧縮されているため、この利点は適用されません。
<!-- 非効率的、すべてのケースで必要とは限りません -->
<script src="utils.js"></script>
<script src="api.js"></script>
<scriptsrc="main.js"></script>
<!-- 最適化済み - 論理的に結合できる場合 -->
<script src="app.bundle.js" defer></script>
HTTP/2やHTTP/3などの最新のHTTPプロトコルを利用することも効果的です。これらのプロトコルでは多重化がサポートされ、単一の接続で複数のリクエストを同時に送信できるため、オーバーヘッドが最小限に抑えられます。クライアント側のリダイレクトを減らすことも、不要なレイテンシを排除するために役立ちます。リダイレクトがあると、そのたびに余分なラウンドトリップが追加され、ページの読み込みが遅くなります。
サーバーの応答時間の短縮
高速で応答性の高いユーザーエクスペリエンスを提供するためには、サーバーの応答時間を最適化することが重要です。最も効果的な戦略の1つは、コンテンツデリバリーネットワーク(CDN)を使用することです。CDNは、地理的にユーザーの近くにあるエッジロケーションから画像、JavaScript、CSSファイルなどの静的アセットを提供することでレイテンシを削減します。最初のバイトまでの時間(TTFB)を短縮すると、パフォーマンスが大幅に向上する可能性があります。これは、データベースクエリの改善、ミドルウェアのオーバーヘッドの削減、サーバーロジックの最適化など、バックエンド処理を最適化することで達成できます。
APIの効率性も関係があります。API呼び出しの数を最小限に抑え、適切な場合は結合し、リクエストの重複を回避すると、ネットワークのオーバーヘッドを減らすことができます。コンテンツ配信を高速化するには、サーバーサイドレンダリング(SSR)または静的サイト生成(SSG)の使用を検討します。これはHTMLをサーバー上で事前にレンダリングするため、ページの読み込みが速くなり、最初のコンテンツの描画(FCP)が改善されます。FCTとは、ブラウザがコンテンツの最初の部分をレンダリングするまでにかかる時間です。また、最も重要なコンテンツを最優先するために、遅延読み込みのテクニックを使用して、重要でないデータや補助的なデータの読み込みを遅らせることもできます。
レンダリングとJavaScriptの実行の最適化
高速で応答性の高いウェブアプリを作成するには、レンダリングとJavaScriptの実行を最適化します。重要な方針の1つは、ページの読み込み中に負荷の高い計算や不要なロジックによってメインJavaScriptスレッドがブロックされるのを防ぐことです。メインスレッドがブロックされると、レンダリングが遅延してドロップフレームが発生し、ユーザーエクスペリエンスに悪影響が及ぶ可能性があります。
これを軽減するには、JavaScriptを軽量に保ち、最初の読み込み時は必要なコードのみを実行します。この方針は入力イベントの処理にも適用されます。入力ハンドラーは、フレームの完了を妨げたり、不要なレイアウト処理を追加したりする可能性があるため、アプリの滑らかさに影響するパフォーマンスの問題を引き起こすことがあります。そこで、ハンドラーはデバウンスすることをお勧めします。つまり、イベントの値を保存して、次のrequestAnimationFrameコールバックでスタイルの変更を処理します。
ページのレンダリングがブロックされるのを防ぐために、すぐには必要とされないスクリプトは、async属性またはdefer属性を使用して非同期で読み込みます。これにより、レンダリングをブロックするJavaScriptの影響が軽減されます。
// JavaScriptを非同期で読み込みます。
<script src="analytics.js" defer></script>
// 必要時に動的にデータ/JavaScriptをインポートします。
import('./data.js').then(initData);
コード分割を使用すると、JavaScriptモジュールの動的な読み込みが可能になり、ページや機能ごとに必要なスクリプトだけを読み込むことができます。よりスムーズなアニメーションを実現し、視覚的なパフォーマンスを改善するには、transformとwill-changeのようなCSSプロパティを使用してアクセラレーションを有効にします。CSSを通じたGPUアクセラレーションは、レンダリングをGPUにオフロードするために役立ちます。これらの戦略により、ウェブアプリの体感的なパフォーマンスと実際のパフォーマンスが向上します。
JavaScriptを最適化するもう1つの方法として、ウェブワーカーがあります。これは、スクリプトをバックグラウンドで実行できるようにするものです。詳細については、ウェブアプリのウェブワーカーに関するベストプラクティスを参照してください。
リソースのキャッシュ
キャッシュを使用すると、ウェブアプリのパフォーマンスと応答性が高まります。クライアント側のキャッシュを有効にするには、JavaScriptファイル、CSSスタイルシート、データ、画像などのリソースに対して適切なCache-Controlヘッダーを設定します。これにより、ウェブアプリでこれらのアセットを保存して再利用することが可能になり、何度もダウンロードする必要がなくなります。また、CDNキャッシュを利用すると、ユーザーの近くにあるエッジロケーションから静的コンテンツが提供され、読み込み時間が大幅に短縮される可能性があります。クライアントキャッシュとCDNキャッシュを組み合わせることで、開発者はサーバーの負荷を軽減し、レイテンシを減らし、よりスムーズなエクスペリエンスをエンドユーザーに提供できます。
スクロールパフォーマンスの向上
アプリのスクロールパフォーマンスを向上させるには、考慮すべき点がいくつかあります。まず、offsetTopやscrollHeightなどのレイアウトプロパティには、スクロールイベントハンドラーから頻繁にアクセスしたり変更を加えたりしないようにします。これらを変更すると、そのたびにレイアウトの再計算が必要になるため、パフォーマンスに影響が及びます。スロットリングやデバウンスのメカニズムを使用して、スクロールイベントの処理頻度を制限することもできます。強制的なリフローを防ぐために、スクロールリスナーの内部では、レイアウトの同期的な読み込みや書き込みを避けることをお勧めします。
ページ上のすべてのコンテンツやスクロールリスト全体をレンダリングするのではなく、表示されている要素や必要な要素のみをレンダリングします。スムーズなスクロールを実現するには、GPUアクセラレーション対応のCSSプロパティを使用することも効果的です。たとえば、CPU負荷の高いtop、left、widthなどのプロパティの代わりに、transformを使用します。
Chrome DevToolsの [レンダリング] タブには、スクロール中に低速な描画や重複する描画が発生しているレイヤーを視覚的に強調表示する機能があります。このツールを使用すると、パフォーマンスのボトルネックを特定し、スクロール動作を最適化できます。
ウェブアプリのKPIの測定
Vegaには、主要なパフォーマンス指標を高いレベルで測定するVega App KPI Visualizerツールが用意されています。このツールを使用すると、最初のフレームまでの時間(TTFF)、描画完了までの時間(TTFD)、スクロールの滑らかさ、ビデオの滑らかさの指標を測定できます。詳細については、アプリのKPIの測定を参照してください。
より詳細で低レベルな視点からウェブアプリのパフォーマンスを確認するには、Chrome DevTools(CDT)を使用します。Chromeツールに含まれている [パフォーマンス] タブ、[ネットワーク] タブ、Lighthouseを使用すると、ベンチマークを監査したり、ウェブアプリのホットスポット(HTML/JS/CSS/画像)を特定したりでき、アプリのパフォーマンスを改善するために役立ちます。現在、LightHouseはVegaで機能しませんが、ウェブアプリをデスクトップ版Chromeで直接読み込み、適切なネットワーク制限とCPU制限を適用してデバッグできます。
関連トピック
Last updated: 2025年10月7日

