【入門編】 Long Tasks APIによるメインスレッド監視 – Webブラウザの仕組み実践ガイド

おい、そこの君! ちょっとウェブサイトを開いてみてくれないか? うん、ありがとう。

どうだい? スクロールはスムーズかい? ボタンをクリックしたら、すぐに反応してくれたかい? もし「んー、ちょっと引っかかるな」「あれ、今一瞬固まった?」なんて感じたとしたら……そう、今日まさに話したい「メインスレッドの長いお仕事」が原因かもしれないんだ。

僕らはウェブの世界で、ユーザーが「気持ちいい!」と感じる体験を届けるために、日々奮闘している。その中で、時としてウェブサイトが「もっさり」したり「カクカク」したりする、あのイライラ感。あれはね、実はブラウザの心臓部が悲鳴を上げているサインなんだ。

今日は、その悲鳴をキャッチするための、まるで探偵のような頼れるツール「Long Tasks API」について、現場の泥臭さも交えつつ、とことん優しく深掘りしていこう。大丈夫、難しい話は僕が噛み砕くから、安心してついてきてくれ!

—

1. ウェブサイトの「もっさり」感、その正体は何だ?

君も経験があるだろう? あるウェブサイトにアクセスしたら、画像が表示されるのが遅いとか、フォームに入力しようとしたらキーボードの入力がワンテンポ遅れるとか、ボタンを押してもすぐに反応しないとか。まるで、急いでいる時にレジの店員さんが一人でてんやわんやしているような、そんな状況だ。

僕らのウェブサイトは、見えないところで本当にたくさんの仕事をこなしている。JavaScriptの実行、HTMLやCSSの解析、画面のレイアウト計算、画像の描画、ユーザーからの入力(クリックやスクロール)への対応……これら全てを、ブラウザの中にあるたった一つの「メインスレッド」という司令塔が、文字通り「一人で」頑張って処理しているんだ。

そう、まるでレストランの腕利きシェフが、注文の受付から調理、盛り付け、配膳まで、全部一人でやっているようなイメージだよ。

〇 メインスレッドは「ウェブサイトの心臓」

この「メインスレッド」は、ウェブサイトがユーザーとインタラクションするために欠かせない、まさに心臓のような存在だ。ユーザーが「このボタンを押したい!」と思ったら、メインスレッドがそのクリックイベントを受け取り、「この色に変わって!」「このアニメーションを動かして!」と指示を出す。そして、その指示通りに画面が変化するんだ。

もし、このメインスレッドが、何か時間のかかる重い作業(例えば、ものすごく複雑な計算や、大量のデータ処理)に取り掛かってしまったらどうなると思う?

そう、他の全ての作業がストップしてしまうんだ。ユーザーがスクロールしようとしても、クリックしようとしても、メインスレッドは前の重い作業で手一杯だから、何も反応できない。結果として、ウェブサイトは「固まった」ように見え、ユーザーは「あれ?壊れたのかな?」と不安になってしまう。これが「もっさり」感や「カクカク」感の正体さ。

〇 ユーザー体験を左右する「50ミリ秒の壁」

じゃあ、どれくらいの時間メインスレッドが忙しいと、ユーザーは「遅い」と感じ始めるんだろう?

僕たちの脳は本当に優秀で、特に「動き」に対しては敏感なんだ。ウェブサイトがスムーズに動いていると感じるためには、1秒間に約60回の画面更新(これを60fps、つまりフレーム/秒と呼ぶ)が必要だと言われている。単純計算すると、1回の画面更新にかかる時間は約16ミリ秒(1000ms ÷ 60fps ≈ 16.6ms)以下でなければならない。

でもね、ユーザーが「何か遅いな」と明確に感じ始めるのは、大体50ミリ秒を超えたあたりからだと言われている。これは、ウェブの第一線で戦う僕らの経験則であり、様々な研究で裏付けられた「壁」なんだ。

想像してみてくれ。ボタンを押した時に、50ミリ秒以上も反応がなかったら、君はきっともう一度ボタンを押してしまうだろう? そして、もしウェブサイトがアニメーション中に50ミリ秒以上固まってしまったら、それはもう「カクカク」というより「ガタガタ」だよ。

だから、この「50ミリ秒」という数字は、僕らがユーザー体験を考える上で、非常に重要な目安になるんだ。メインスレッドが50ミリ秒以上、一つの作業に専念して他のことを一切できない状態を、僕らは「Long Task(ロングタスク)」と呼ぶ。

—

2. 「Long Tasks API」ってどんな探偵?

さて、メインスレッドが50ミリ秒以上忙しくしていると、ユーザー体験が悪くなることは分かった。でも、一体「どんな作業が」「どこで」「どれくらいの時間」メインスレッドを占有しているのか、どうやって知ればいいんだろう?

ここで登場するのが、今日の主役 Long Tasks API だ!

このAPIはね、例えるなら「メインスレッドの作業時間を監視してくれる、超優秀なタイムキーパー兼探偵」のような存在なんだ。

〇 優秀な監視カメラ「PerformanceObserver」

Long Tasks APIは、`PerformanceObserver` という仕組みを使って動く。これは、ブラウザのパフォーマンスに関する特定のイベント(今回なら「Long Task」)が発生した時に、「おや?何かあったぞ!」と教えてくれる監視カメラみたいなものなんだ。

僕らがこの`PerformanceObserver`に「メインスレッドの長い作業を監視してくれ」と依頼すると、あとは自動的にブラウザが50ミリ秒を超える作業を検出し、その詳細を僕らに報告してくれる。

〇 何を探しているの?

Long Tasks APIが探しているのは、文字通り「50ミリ秒以上の時間、メインスレッドを独占した作業」だ。

「このJavaScriptの関数が300ミリ秒もかかって実行されたぞ!」
「このレイアウト計算が100ミリ秒もかかって、画面が固まったぞ!」

こんな風に、原因になりそうな処理を見つけてきてくれるんだ。これって、パフォーマンス改善の最初の一歩として、めちゃくちゃ重要だと思わないかい? どこに問題があるか分からないと、改善のしようがないからね。

—

3. さあ、実践!メインスレッドの忙しさを見張ろう

よし、理屈は分かった。じゃあ、実際にこのLong Tasks APIを使って、メインスレッドがどんな風に忙しくしているのか、監視してみようじゃないか!

難しいコードは極力避けて、誰でもすぐに試せるシンプルな例を提示するから、君もぜひ手元のエディタにコピペして、ブラウザの開発者ツールを開きながら動かしてみてほしい。

〇 サンプルコードを動かしてみよう!

まずは、以下のHTMLファイルを適当な名前(例えば `long-task-monitor.html`)で保存して、ブラウザで開いてみてくれ。そして、開発者ツール(ChromeならF12、FirefoxならCtrl+Shift+I、MacならCmd+Option+I)を開いて、`Console` タブを見ておいてくれよ。






Long Tasks APIでメインスレッドを監視しよう


メインスレッドの「長いお仕事」を監視してみよう!

下のボタンを押すと、メインスレッドが一時的に忙しくなります。

監視を開始しました。開発者ツールのConsoleタブを見てください。

「長いお仕事」が検出されると、ここにメッセージが表示されます。



〇 コードの丁寧な解説

どうだい? ボタンを押してみたかな? おそらく、ボタンを押した瞬間、一瞬画面が固まったように感じただろう。そして、開発者ツールのコンソールには、こんなメッセージが表示されたはずだ。

Long Tasks の監視を開始しました。
「長いお仕事」を開始します...
Long Task が検出されました!
タスクの種類: script
かかった時間: XXX.XX ミリ秒 (←ここが50msより大きい数字になっているはず!)
開始時刻: YYY.YY ミリ秒
原因: script (...)
「長いお仕事」が終了しました。かかった時間: XXX.XXms
最終結果 (意味はないけど): ZZZZ

一つずつ見ていこう。

1. `new PerformanceObserver((entryList) => { ... });`

  • これが「監視員」を雇っている部分だ。丸括弧の中は、監視員が何かを発見したときに「よし、報告だ!」と呼び出してくれる関数だよ。
  • `entryList` には、今回発見された「Long Task」の情報がズラッと詰まっている。

2. `observer.observe({ entryTypes: ['longtask'] });`

  • これは監視員に「Long Task という種類のイベントを監視してくれ!」と指示している部分だ。他にも色々なイベントを監視できるけど、今回は「長いお仕事」に絞っている。

3. `for (const entry of entryList.getEntries()) { ... }`

  • 監視員が報告してくれたLong Taskのリスト (`entryList`) を、一つずつ丁寧に見ていくループだ。
  • `entry` オブジェクトが、一つのLong Taskに関する詳細な情報を持っている。

4. `entry.name`:

  • これは、検出されたLong Taskの種類を示している。僕らの例では「`script`」と表示されたはずだ。これは、JavaScriptの実行が原因でLong Taskが発生したことを意味している。他にも「`layout`」(画面のレイアウト計算)や「`paint`」(画面の描画)といった種類もあるよ。

5. `entry.duration`:

  • これがまさに、そのLong Taskが「どれくらいの時間」メインスレッドを占有したか、ミリ秒単位で示してくれる値だ。僕らの設定した「50ミリ秒の壁」を確実に超えているはずだよね!

6. `entry.startTime`:

  • そのLong Taskが「いつ」始まったかを示してくれる。ウェブサイトがロードされてから何ミリ秒後か、という時間だよ。

7. `entry.attribution`:

  • これはすごく便利な情報だ! もしブラウザがサポートしていれば、「そのLong Taskを引き起こした根本的な原因は何だったのか?」 を教えてくれるんだ。僕らの例だと、自分で書いたスクリプトなので「`script`」と表示されているけど、もし外部のライブラリやフレームワークが原因なら、その名前が表示されることもある。これは、ボトルネックを特定する上で非常に強力なヒントになるぞ!

僕らが意図的に仕込んだ `for` ループが、メインスレッドを何百ミリ秒も占有し、それがLong Taskとしてしっかり検出されたのが分かっただろう?

---

4. Long Tasks APIが教えてくれること、そしてその先へ

Long Tasks APIを使うことで、単に「ウェブサイトが遅い」と感じていた漠然とした不安が、「あ、このJavaScriptの処理が300ミリ秒もかかってたのか!」という具体的な情報に変わる。

これはもう、問題を解決するための最初の一歩であり、最も重要な一歩だ。だって、どこに問題があるか分からないと、どうしようもないからね。

〇 ボトルネックの特定と改善への道筋

Long Tasks APIが教えてくれる情報(タスクの種類、かかった時間、そして何より `attribution` による原因のヒント)があれば、君は次に何をすべきかが見えてくるはずだ。

  • `script` が原因なら?
  • 「よし、このJavaScriptの処理をもっと高速化できないか?」と考える。計算量を減らす、処理を分割する、非同期処理に切り替える(後述のWeb Workerも視野に入れてみよう!)、といった改善策が考えられる。
  • `layout` が原因なら?
  • 「CSSの変更が、こんなに大規模なレイアウト計算を引き起こしていたのか!」と気づく。CSSの書き方を見直したり、アニメーションのプロパティを最適化したりといったアプローチが考えられる。
  • 特定の外部ライブラリが原因なら?
  • 「このライブラリ、ちょっと重すぎるんじゃないか?」と疑う。より軽量な代替品を探すか、そのライブラリを使う部分を最適化できないか検討する。

このように、Long Tasks APIは、まるで「ウェブサイトの健康診断結果」をくれるお医者さんのような存在なんだ。どこが悪いのかを教えてくれるから、適切な治療法を見つけられる。

〇 継続的なモニタリングの重要性

一度改善したら終わり、ではないのがウェブの世界の面白いところであり、大変なところでもある。新しい機能を追加したり、ライブラリを更新したりすると、またどこかでLong Taskが発生してしまうかもしれない。

だから、Long Tasks APIのようなツールは、開発の初期段階だけでなく、ウェブサイトを運用していく上で継続的に監視し続けることが本当に重要なんだ。ユーザーが気づかないうちに発生している小さなパフォーマンスの問題も、このAPIはしっかり見つけてくれるからね。

---

5. チーフアーキテクトが語る、現場のリアルな知見

ここまで、Long Tasks APIの基本的な使い方と重要性を伝えてきたけれど、ここからは現場の最前線で何年も戦ってきた僕から、もう少し深い話をしておこうか。

〇 50ミリ秒はあくまで「目安」

「50ミリ秒を超えたらアウト!」と話してきたけれど、これはあくまで一般的な目安だ。

例えば、ユーザーがボタンを押しっぱなしにして何かをドラッグするようなインタラクティブなアプリケーションや、リアルタイム性が求められるゲームなどでは、50ミリ秒どころか16ミリ秒(1フレームの時間)を超えただけでも、ユーザーは「遅い!」と敏感に感じてしまうことがある。

逆に、ウェブサイトのロード直後の一瞬だけ発生する、ユーザーがまだ何も操作していないようなLong Taskであれば、そこまで致命的ではない場合もある(もちろん、ない方が良いに決まっているけどね)。

つまり、このAPIで検出されたLong Taskは、その発生したタイミングやユーザーがその時何をしていたか、ウェブサイトの目的などを考慮して、「本当にユーザー体験に悪影響を与えているのか?」 を判断する目を持つことが大切なんだ。

〇 メインスレッドを解放せよ!「Web Worker」との連携

もし、どうしても時間のかかる重い計算処理が必要な場合、どうすればメインスレッドを占有せずに済むと思う?

ここで登場するのが、Web Worker という技術だ! これはね、メインスレッドとは別の「裏方さん」を雇うようなイメージなんだ。重い計算やデータ処理をこのWeb Workerに任せることで、メインスレッドはユーザーからの入力や画面描画といった「表舞台」の仕事に専念できる。

Long Tasks APIで「あ、この処理が重いな」と特定できたら、「これはWeb Workerに任せられないかな?」と考えるのは、パフォーマンス改善の常套手段だよ。メインスレッドは、常に軽やかに動いているべきなんだ。

〇 開発者ツールの「Performance」パネルとの組み合わせ

Long Tasks APIはプログラムで監視できる便利なツールだけど、ブラウザの開発者ツールには、もっと視覚的にパフォーマンスの問題を分析できる強力なツールがあるのを知っているかい?

そう、「Performance」パネルだ! ここでは、ウェブサイトの動作を記録し、どの関数がどれくらいの時間かかったか、レイアウト計算や描画にどれくらい時間がかかったか、JavaScriptの実行と画面の更新がどう連動しているかなど、まるで映画のフィルムのように詳細な情報を確認できるんだ。

Long Tasks APIで「ここが怪しい!」と目星をつけたら、Performanceパネルでその時間帯の動作を記録して、さらに深く掘り下げて原因を特定する。この組み合わせは、まさに最強のデバッグコンビだと言えるね。

〇 JavaScriptだけじゃない、レイアウト計算も忘れずに

僕らの例ではJavaScriptの重いループがLong Taskの原因だったけど、実はCSSの変更やDOM操作によって引き起こされる「レイアウト計算(リフロー)」や「再描画(リペイント)」も、メインスレッドを大きく占有するLong Taskになり得るんだ。

特に、要素の幅や高さ、位置などをJavaScriptで頻繁に読み書きしたり、多数の要素のCSSプロパティを一度に大きく変更したりすると、ブラウザは画面上の全ての要素の位置やサイズを計算し直さなければならなくなる。これが、とんでもないLong Taskになることがあるんだ。

だから、Long Tasks APIで `entry.name` が `'layout'` や `'paint'` と表示されたら、「CSSやDOM操作の仕方に問題があるんじゃないか?」と疑ってみる目も持っておこう。

---

6. おわりに:ユーザーのためのパフォーマンス改善、その一歩

どうだったかな? Long Tasks APIが、単なる技術的なAPIというだけでなく、僕らがユーザーに届ける体験の質を左右する、本当に大切なツールだということが伝わっただろうか。

ウェブサイトのメインスレッドは、まるでレストランの腕利きシェフだ。一つ一つの注文(ユーザーの操作)に素早く、丁寧に応えることで、お客さん(ユーザー)は「このお店、最高!」と感じてくれる。もしシェフが裏で長い時間、無駄な作業に追われていたら、お客さんはどんどんイライラして、ついにはお店から去ってしまうだろう。

Long Tasks APIは、そのシェフが「いつ、どんな作業で、どれくらい手一杯だったか」を教えてくれる、貴重な記録なんだ。この記録を読み解き、原因を見つけ、改善していくことで、僕らはもっと快適で、もっと「気持ちいい」ウェブ体験をユーザーに届けることができる。

パフォーマンス改善は、ウェブ開発における永遠のテーマだ。でも、恐れることはない。今日の話が、君がそのテーマに挑むための一歩になったなら、僕もチーフアーキテクト冥利に尽きるよ。

さあ、今日から君も、ウェブサイトの「もっさり」感の正体を探る、探偵の目を持ってみないか? きっと、新しい発見と、ユーザーの笑顔が待っているはずだ!

頑張れ、未来のウェブスペシャリストたちよ!

コメント

タイトルとURLをコピーしました