ブラウザのメインスレッドは高価——UIを凍らせる真犯人はコードの遅さではない
The Browser's Main Thread Is Expensive
フロントエンド最適化というと、ネットワークリクエスト削減やバンドル縮小、キャッシュ活用を思い浮かべる人が多い。しかし、操作が多い画面やライブ配信のチャットのように動きの激しい画面では、メインスレッドの占有が原因でスクロールや入力がカクつく。コードが遅いのではなく、メインスレッドを長時間専有するタスクが問題だ。本稿では、メインスレッドの役割と、タスクを分割・バッチ化・優先順位付け・遅延させることで、限られた時間を効率的に使う方法を解説する。特に、チャットの一括描画を分割してyieldする具体例や、アニメーション中に時間ベースで分割するテクニックを紹介。
コードは遅いわけではない。ただ、たまたまメインスレッドを握っているコードなのだ。
HNでの議論
126- martinald
良い記事であり、これがもっと広く知られるべきだと思います。
問題は、それがインタラクティブ性に焦点を合わせすぎていることです。実際には、遅いサイトの90%以上は、本当にインタラクティブ性が原因で遅いのではなく、巨大なreact/nextjsのバンドルを配信し、非常に重いハイドレーション作業をしなければならないからです。
多くのサイトが10MBを超えるバンドルを持っており、それをダウンロードして解析し、ハイドレーションする必要があります。
私は、複数のSPAが内部に積み重なっているサイトも(多く)見たことがあります。
遅いインターネット接続やCPUを使用している場合、ページは数十秒間基本的に使用できず、バンドルハイドレーション後の譲歩(yielding)ではそれを本当に解決できません。
- nerdralph
記事のほとんどに同意しますが、次の点を明確にしたいと思います:
> 画面を滑らかに見せるためには、フレームをディスプレイのリフレッシュレートで描画する必要があります。最も一般的な60Hzディスプレイでは、毎秒60フレーム、つまり1フレームあたり約16.6ミリ秒です。
ディスプレイのリフレッシュレートに完全に一致させることは絶対に必要ではありません。144Hzモニターでは、72FPSは大多数の人にとって滑らかに見えるでしょうし、48FPSでもほとんどの人にとって滑らかに見えるでしょう。より高いFPSが良いことには同意しますが、逓減する利点があります。
- jonathanlydall
素晴らしい記事です。
私自身、レンダリングの「スレッド」がどのように機能し、ブロックするかについて直感的な理解を深めてきたため、これらのテクニックのいくつかを自分で適用してきましたが、この記事には私にとって新しい情報はほとんどありませんでした。しかし、経験の浅い開発者にとっては、この記事は非常に啓発的であり、何が起こっているのかについてのしっかりした理解を提供するはずです。
私は約15年前に作った趣味のプロジェクト[0]で、特にキャンバス上で多くの描画操作を行う必要がある場合に、譲歩(yielding)を使用しました。また、ワーカースレッドを使用してその一部をバックグラウンドスレッドでレンダリングする実験もしましたが、当時はメインスレッドと効率的にデータをコピーする方法がなく、データをbase64エンコードされたPNGとして送信する必要があり、エンコード、デコード、キャンバスへのコピーのオーバーヘッドにより、すべてをメインスレッドで行うよりもはるかにパフォーマンスが悪くなりました。
そのウェブサイトはまた、アップロードされたファイルのGzipデコードをJavaScriptで行っており、当時見つけたライブラリはすべての作業を同期的に行っていたため、UIスレッドを10秒以上簡単にロックアップする可能性がありました。私はそれを200ミリ秒ごとに譲歩できるように調整しました。そのプロセスは非常に勉強になりました。特に、if文の後に中括弧を決して省略しないように確信させられたからです。なぜ機能しないのかを理解するのに非常に長い時間を費やし、最終的に追加したステートメントがif文のブロック内にないことに気づきました。if文の仕組みを理解していなかったわけではなく、私の頭の中で欠けていたのは[…]
- larodi
トップ記事です、称賛します!以前にこれらのテクニックのいくつかを適用しましたが、それらは非常に重要です。問題は、JSを学んだり教えたりするとき、これらのトピックについて話す時間が限られていることが多く、それらは見た目以上に重要であるということです。
協調的マルチタスクの要点は、時々(ランナーに)譲歩して、描画を処理できるようにすることです。さらに、60fpsでは、Nフレームごとに計算できることが非常に多く、目はそれを見ず、アニメーションは流れます。
WebGPUが関与するとさらに興味深くなりますが、CSSアニメーターは確かに非常に高速です。
注:最近の私の作品(ニュースクールデジタルフライヤーサイト)-> bsf.hmsu.org // nouveauxhivers.dub4powder.xyz
- piker
素晴らしい記事です、OP。私たちはWASMで作業しており、そのコンテキストでメインスレッドから離れてドキュメントのレンダリングを支援するためにウェブワーカーを検討しています。ArrayBufferが参照によってのみ移動されることを読んで驚きました。それがオプションになるかもしれません。まとめてくれてありがとう。
- gwbas1c
参考までに:これはブラウザだけの問題ではありません。すべてのプラットフォーム(Windows、Mac、iOS、Android)は通常、シングルスレッドのUIを持っています。
- jkhdigital
この記事は次のステートメントで締めくくられています:
> 開発の多くはトレードオフであり、状況に応じて選択しなければならず、最終的には開発者の経験と判断に帰着します。
素晴らしい記事ですが、スケジューリングの問題を「経験と判断」の問題として捉えるのは少し時代遅れだと思います。希少なリソースへの作業の割り当ての問題は、コンピュータサイエンス全体で最も古く、最もよく研究されている問題の1つです。車輪の再発明を試みる前に、教科書を参照するのが理にかなっているでしょう。
- skobes
「FLIP(First, Last, Invert, Play)」の議論は、基本的にこのテクニックを自動化するために存在するView Transitions APIに言及することで改善されるでしょう。