Open15

【フロントエンド編】パフォーマンスチューニング

まさきちまさきち

パフォーマンスチューニング

https://qiita.com/nuko-suke/items/50ba4e35289e98d95753

https://qiita.com/nuko-suke/items/22702472543bfd3e585f#バンドルされたファイルを眺める


  1. フェッチ時、Keep-Aliveを指定する。
    Keep-Alive は HTTP の下のレイヤーの TCP/IP 通信を効率化する仕組み

https://qiita.com/toshihirock/items/8d9d1cce4c04284be4c4

  1. キー/バリューを頻繁に追加や削除する場合はMapを使用する。


  1. 画像はWebPやAVIFを使用する
  2. 疑似要素の before や after を使えば必要以上な DOM の作成を抑えることが可能。
  3. TreeShaking を有効化する
  4. Amazon CloudFrontなどのCDNを活用
  5. Cache-Control
まさきちまさきち

imgタグ:decoding と loading 、 fetchpriority 属性を指定する

※ 画像は必ずalt・width・height・decoding=”async”属性を必須で設定する

<!-- 優先度の高い画像 -->
<img
  src='...'
  decoding='async'
  loading='eager'
  fetchpriority='high'
>

<!-- 優先度の低い画像 -->
<img
  src='...'
  decoding='async'
  loading='async'
  fetchpriority='low'
>

decoding

画像のデコードを同期 or 非同期に処理するかを指定できる。
この属性は 画像読み込みの優先度に関わらず非同期( decoding=async )を指定する(同期的な処理はブラウザをブロッキングしてしまう為)


loading

画像などの読み込みを即時 or 遅延の指定が可能。
ファーストビューで表示される優先度の高い画像は即時読み込み loading='eager' 、それ以外のファーストビュー以外の画像にはloading=”lazy” で遅延読み込みする


fetchpriority

読み込みの優先度の高い画像は fetchpriority='high' 、 低い画像は fetchpriority='low' を指定する



imgタグ:width/height属性を指定する

<img
  width="800" 
  height="450"
/>

imgタグのwidth/height属性を指定するとブラウザのレンダリングの助けになる(ブラウザは画像がロードされる前に適切なスペースを確保しレイアウトのシフトを防ぐことができる)
※ レスポンシブの場合は、最終的な見た目はCSSで定義されたものが優先される為、今まで通りサイズ指定を行っていて問題ない。

https://itokoba.com/archives/7047#:~:text=width 属性は画像の,比率を指定します。&text=この属性の値は,なければなりません。



<!-- 優先度の高い画像 -->
<!-- link タグは head タグの中で -->
<link
  rel='preload'
  as='image'
  href='...'
  fetchpriority='high'
>

link タグ rel=preload を指定すれば、ページ読み込みが開始される早期の段階で事前に画像などのリソースを読み込んでおくことができる。読み込みの優先度高い画像にはこのような link タグ rel=preload を指定して先読みしておける。


背景画像はimg要素で指定する

背景画像はimg要素で設置する(HTML側に設置することで遅延読み込みが可能になる)


まさきちまさきち

アイコン画像を使用しない: SVGや HTML/CSS を使ってアイコンを表示する

複雑なアイコンでなければインラインで SVG を埋め込んだり外部から画像をリクエストせず HTML/CSS を使ってアイコンを表示する。
SVGはベクター形式の画像の為、拡大縮小しても画質が劣化しない。

https://svg-tutorial.com/

まさきちまさきち

非同期処理

Promise.allの使用

依存関係のない複数の非同期処理を実行しているのならば、Promise.allを使用する(失敗扱いにしたくない場合はPromise.allSettledを使用する)
Promise.allを使用ことで、複数の非同期操作を並行して実行し、全体の待ち時間を減らすことが可能。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/all


非同期処理を待たなくて良い場合

非同期処理を待たなくて良いところは、awaitを使用しない。

const sendErrorToServer = async (message) => {
  // サーバーにエラー情報を送る処理
};

console.log('何かエラーが起きた');
// 後続の処理はサーバーにエラー情報を送る処理とは関係ないので await をつけない
sendErrorToServer('エラーです');
console.log('後続の処理');


先に非同期処理処理を行う

時間がかかる非同期処理を先に記載する。


不要なPromiseの排除

非同期処理が必要ない場合にPromiseを使うと、パフォーマンスが低下する可能性があります。同期的に実行できる処理は、Promiseを使わずに同期的に行うべき。


非同期処理の遅延実行

すぐに実行する必要がない非同期処理は、遅延して実行する(setTimeoutを使って非同期処理の開始を遅らせる)

まさきちまさきち

Core Web Vitals(コア・ウェブ・バイタル)について

Core Web Vitals(コア・ウェブ・バイタル)の改善が表示速度・パフォーマ ンスの最適化、SEO対策につながる。

  1. Largest Contentful Paint /ページの表示速度(読み込み時間)
    ビューポート内に表示される最も大きい画像またはテキスト ブロックレン
    ダリング時間を、ページの初期読み込み開始タイミングと比較した時間(2.5秒以下が理想)


  1. First Input Delay/ユーザー操作への反応性(インタラクティブ性)
    ユーザーが最初にページを操作したとき、その操作に応じてブラウザーが実際にイベント ハ ンドラーの処理を開始するまでの時間(100 ミリ秒以下が理想)


  1. Cumulative Layout Shift/ページコンテンツ視覚的な安定性
    ユーザーが予期しないレイアウト シフトに遭遇する頻度を数値化に役立つ 指標であり、CLS が低ければ低いほど、そのページが快適であることが保証される(スコアが 0.1 以下が理想)


Core Web Vitalsについては以下動画で詳細に解説されている。
https://www.youtube.com/watch?v=pqyyGdtok4Q&list=WL&index=1&t=679s

まさきちまさきち

filter vs Map

「要素数が小さい配列を」「頻繁に(多数)処理する」という前提がある場合はfilterを使用することで効率が良くなる(SetやMapを使わない)

https://zenn.dev/bje35149/scraps/de2c79c950dffb

データ量が多いときはArray.prototype.filter()ではなくMapを使用する。

/**
 * IDが重複している要素を除去した配列を返す
 * @param items keyにidが存在するオブジェクトからなる配列
 * @returns ID重複のないオブジェクトの配列
 */
export const deleteDuplicateIdItem = <T extends { id: number }>(
  items: T[]
): T[] => {
  return Array.from(new Map(items.map((item) => [item.id, item])).values())
}
まさきちまさきち

setTimeoutによるパフォーマンス改善

setTimeoutはタスクを分割してタスクキューに追加してくれる
長いタスクを分割し、緊急性のないものはあと回しにする(ユーザーの画面に影響のない処理など)ことが可能。

https://qiita.com/nuko-suke/items/5b16ab9de402547c5797


長いタスクとは...50 ミリ秒を超える処理

https://web.dev/articles/long-tasks-devtools?hl=ja#:~:text=The RAIL model では、100 ミリ秒以内に視覚的な応答を得るには、ユーザー入力イベントを 50 ミリ秒で処理することを推奨

メインスレッドを長時間独占して UI を「フリーズ」させるJavaScriptのコードのこと

ウェブページの読み込み中に、長時間のタスクによってメインスレッドが動作しなくなり、準備ができたように見えても、ページがユーザー入力に反応しなくなることがあります。イベント リスナーやクリック ハンドラなどがまだアタッチされていないため、多くの場合、クリックとタップは機能しません。

まさきちまさきち

フロントエンドエンジニアが対応できる技術 的なSEO対策

  1. 検索エンジンにWebサイトの情報が正しく伝わるように作成する。
  2. クローラーがWebサイトをクロール(巡回)しやすいように作成する。


普段意識していること

  • サイト上のすべてのページに<title> 要素でページタイトルが指定される
  • <title> 要素に具体的で分かりやすいテキストを記述する(テキストの繰り返しや定型文は避ける)
  • どのテキストがページのメインタイトル(大見出し)かを明確にする
  • 見出し、段落、リスト、セクションなどコンテンツ内容に応じて意味のあるHTML要素を記述する(全てdivにすると、検索エンジンが混乱する為、divやspanなど意味のないタグは最後にする)
  • 見出しレベルをh1、h2と順に設定する
  • WebP対応
  • 画像・CSS・JavaScriptなどリソースの軽量化


重複コンテンツの削除

まさきちまさきち

MacのRetinaディスプレイについて

ファーストビューの画像は4倍の大きさで、それ以外の画像は3倍の大きさにしてGIMPを用いてWebPへ変換して容量を小さくしてから掲載する

https://www.gimp.org/


まさきちまさきち

defer属性、async属性について

JavaScriptファイルが同期的に読み込まれる(<script>タグのデフォルトの挙動)と、ブラウザはそのファイルのダウンロードと実行が完了するまでHTMLの解析を停止するため、パフォーマンスに影響を与える。ファイルを非同期で読み込むのが鉄則。


defer属性

読み込みが非同期で行われる。実行タイミングはドキュメントがパースされた後。Javascriptファイルの読み込み順序は保証される。


async属性

async属性でもJavaScriptを非同期で読み込むことが可能。
実行タイミングはHTMLの解析が完了する前でもスクリプトが取得され次第実行されるので、読み込み順序は保証されない。

https://zenn.dev/mesi/articles/f990a018fd76c6