入力ハンドラは、フレームの完了をブロックし、不要なレイアウト作業を追加する可能性があるため、アプリのパフォーマンスの問題の原因となる可能性があります。
入力ハンドラは、フレームの完了をブロックしたり、不要なレイアウト作業を追加したりする可能性があるため、アプリのパフォーマンス問題の原因となる可能性があります。
概要
- 長時間実行される入力ハンドラは避けてください。スクロールがブロックされる可能性があります。
- 入力ハンドラでスタイルの変更を行わないでください。
- ハンドラをデバウンスします。イベント値を保存し、次の requestAnimationFrame コールバックでスタイルの変更を処理します。
長時間実行される入力ハンドラを避ける
最速の場合、ユーザーがページを操作すると、ページのコンポジタ スレッドがユーザーのタッチ入力を取得し、コンテンツを移動します。これにより、JavaScript、レイアウト、スタイル、ペイントが行われるメインスレッドでの作業は不要になります。
ただし、touchstart、touchmove、touchend などの入力ハンドラをアタッチすると、コンポジタ スレッドはこのハンドラの実行が完了するのを待つ必要があります。これは、preventDefault() を呼び出してタッチ スクロールを停止する可能性があるためです。preventDefault() を呼び出さない場合でも、コンポジタは待機する必要があるため、ユーザーのスクロールがブロックされ、スタッタリングやフレーム落ちが発生する可能性があります。
つまり、実行する入力ハンドラは、コンポジタが処理を行えるように、迅速に実行されるようにする必要があります。
入力ハンドラでのスタイルの変更を避ける
スクロールやタッチなどの入力ハンドラは、requestAnimationFrame コールバックの直前に実行されるようにスケジュールされます。
これらのハンドラのいずれかで視覚的な変更を行うと、requestAnimationFrame の開始時に保留中のスタイル変更が発生します。「大規模で複雑なレイアウトとレイアウト スラッシングを回避する」のアドバイスにあるように、requestAnimationFrame コールバックの開始時に視覚プロパティを読み取ると、強制同期レイアウトがトリガーされます。
スクロール ハンドラをデバウンスする
上記の問題のソリューションは同じです。常に次の requestAnimationFrame コールバックにビジュアルの変更をデバウンスする必要があります。
function onScroll (evt) {
// Store the scroll value for laterz.
lastScrollY = window.scrollY;
// Prevent multiple rAF callbacks.
if (scheduledAnimationFrame)
return;
scheduledAnimationFrame = true;
requestAnimationFrame(readAndUpdatePage);
}
window.addEventListener('scroll', onScroll);
また、入力ハンドラを軽量に保つというメリットもあります。これにより、計算コストの高いコードでスクロールやタッチなどの操作がブロックされることがなくなります。