Virtual DOMはDOM操作の何を解決したのか

Virtual DOMは「速いDOM」ではない

Reactが登場したとき、Virtual DOMは「DOM操作を高速化する技術」と説明されることが多くありました。
しかしこれは半分だけ正しく、半分は誤解です。

Virtual DOMはDOMを速くする技術ではありません。
ブラウザにDOM操作をさせる回数を減らすための仕組みです。

つまり問題はJavaScriptの処理速度ではなく、ブラウザの描画処理にありました。
ここを理解しないと、なぜVirtual DOMが必要だったのか見えてきません。

DOM操作はなぜ重いのか

JavaScriptの変数操作は非常に高速です。

let x = 0;
x++;

この処理はほぼコストがありません。
一方、DOM操作は別物です。

document.getElementById("count").textContent = x;

この1行は単なる代入ではありません。
ブラウザ内部では次の処理が発生します。

  • レンダーツリーの更新
  • レイアウト再計算
  • ペイント

つまりDOMはデータ構造ではなく、画面描画エンジンの一部です。
操作すると描画計算が始まります。

jQuery時代に起きていた問題

jQueryはDOM操作を簡単にしました。
しかし簡単になったことで、逆にDOMを頻繁に書き換えるコードが増えました。

例えば次のコードです。

for(let i=0;i<100;i++){
  $("#list").append("<li>"+i+"</li>");
}

開発者の感覚では100回の文字列追加ですが、
ブラウザの視点では100回のレイアウト更新の可能性があります。

この状態をreflow地獄と呼びます。
スクロールがカクつく、入力が遅れるなどの原因になります。

つまり問題は
DOM操作が遅い
ではなく
DOM更新回数が多すぎるでした。

Virtual DOMの発想

Virtual DOMは、まず画面を書き換えません。
代わりにメモリ上のツリーを書き換えます。

流れは次の通りです。

1. 新しいUI状態を仮想ツリーに反映
2. 以前のツリーと比較(差分検出)
3. 必要なDOM変更だけ実行

これを差分更新(diffing)と呼びます。

つまりReactは「DOMを操作する」のではなく、
どのDOMを操作すべきかを計算しているのです。

なぜ差分検出が効くのか

通常、画面の大部分は変更されません。
例えばカウンターアプリでは、数字だけが変わります。

jQueryのアプローチ:

  • 画面変更処理を人間が書く

Reactのアプローチ:

  • UIを再構築し、変化点だけ適用
setCount(count + 1);

開発者はUI操作を書きません。
状態だけを書きます。

結果としてDOM更新は最小限になります。

「再レンダリング=遅い」という誤解

Reactでは状態変更のたびに再レンダリングが起きます。
これを不安に思う人もいますが、実際には問題ありません。

再レンダリングは「再描画」ではありません。
再計算です。

実際の描画は差分のみです。
つまり全UIを描き直しているわけではありません。

重いのは再レンダリングではなく、
不要なDOM更新です。

なぜ手動最適化では解決できなかったのか

「DOM更新を減らせばよいなら、手動で最適化すればいいのでは」と考えるかもしれません。
理論上は可能ですが、現実的ではありません。

UIが複雑になると次の問題が起きます。

  • どの要素が変更されたか把握できない
  • 変更漏れで画面が壊れる
  • 修正で別のUIが壊れる

つまり最適化が人間の管理能力を超えました。
Virtual DOMは速度改善というより、複雑性の管理のための技術です。

パフォーマンスの本当の効果

Virtual DOMの最大の効果は平均速度の向上ではありません。
最悪ケースの回避です。

DOMを直接操作すると、特定条件で極端に遅くなります。
リスト、テーブル、フォームなどで顕著です。

差分更新により、最悪の遅延が起きにくくなりました。
結果として「常にそこそこ速い」UIになります。

注意点:Virtual DOMは万能ではない

Virtual DOMにも限界があります。

  • 大量リスト描画
  • アニメーション多用
  • 低性能端末

これらでは依然として負荷が大きくなります。
そのため次のような技術が使われます。

  • 仮想スクロール(windowing)
  • メモ化(memoization)
  • 部分レンダリング

つまりVirtual DOMは問題の終着点ではなく、
レンダリング最適化の一段階です。

最後に

Virtual DOMが解決したのはDOM速度ではありません。
人間がDOM更新を管理する問題です。

jQuery時代は、どのUIを更新するかを開発者が考えていました。
Reactでは、状態だけを考えればよくなります。

フロントエンドの進化は高速化の歴史に見えますが、
実際には「複雑さの制御」の歴史でもあります。

Virtual DOMはパフォーマンス最適化というより、
UIの整合性を保つための仕組みです。
その結果として速く見える、という順序を理解すると役割がはっきりします。