入力ハンドラは、フレームの完了を妨げ、追加の不要なレイアウト作業を引き起こす可能性があるため、アプリのパフォーマンスの問題を引き起こす可能性があります。
入力ハンドラは、フレームの完了をブロックし、追加で不要なレイアウト作業を引き起こす可能性があるため、アプリのパフォーマンスの問題の潜在的な原因となります。
まとめ
- 長時間実行される入力ハンドラは避けます。スクロールをブロックする可能性があるためです。
- 入力ハンドラでスタイルを変更しないでください。
- ハンドラをデバウンスし、イベント値を保存し、次の 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);
これを行うと、入力ハンドラを軽量に保つという利点もあります。計算コストの高いコードでスクロールやタップなどの処理をブロックしなくなったのは素晴らしいことです。