【仮想DOMの概念から】なぜSvelteがReactよりも優れているのか


このタイトルだとReactがダメみたいなニュアンスでとられるかもしれませんが、今日の議題であるSvelteが仮想DOMを使用しないことに注目していただきたいです。現在はReactがマーケットの主役であり必須のスキルであることは明らかです。
Svelteのフレームワークは[前回の記事で詳しく説明](https://asameshicode.com/svelte/)しているので是非読んでみてください。
以上を理解していただいたうえで今後のフレームワークを選ぶ材料として下記の記事を読んでいただければと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3001224/ee091863-7417-2ad2-2485-b0d5ad409529.png)

## **DOM操作のコスト**

まずはDOM操作にかかるコストについて理解しましょう。

以下に主要なDOM操作のコストを記載します。



1. レンダリングコスト: DOMの変更がブラウザ上で再レンダリングを行う場合、そのコストが発生します。例えば、要素の追加や削除、スタイルの変更などが該当します。ブラウザは再レンダリングを実行するために計算リソースを必要とし、処理時間がかかることがあります。
2. レイアウトコスト: DOMの変更が要素の配置やサイズに影響を与える場合、ブラウザは再レイアウトを行う必要があります。再レイアウトは要素の位置やサイズを計算し直す処理になり、変更に応じて他の要素も再配置する必要があります。再レイアウトはレンダリングコストよりも高いコストがかかる場合があります。
3. ペイントコスト: DOMの変更が要素の描画に影響を与える場合、ブラウザは再描画（ペイント）を行う必要があります。再描画は要素の内容を実際に画面に描画する処理であり、変更された要素やその周囲の要素が再描画されます。

これらのコストは、DOMの変更が大きい場合や複数の要素に影響を与える場合に増加する傾向があります。したがって、効率的なDOM操作を行うことは、パフォーマンスの向上につながります。

また、注意点として、ブラウザは最適化を行っているため、すべてのDOMの変更が即座にコストを引き起こすわけではありません。一部の変更はバッチ処理されたり、最適化されたりする場合があります。しかし、大量のDOMの変更や頻繁な変更は、パフォーマンスの低下を引き起こす可能性があります。

したがって、DOMの変更は必要最小限に抑えることが重要であることが分かります。


## **仮想DOMの概要**

仮想DOMは、実際のDOMの抽象化をさせる技術であり、Webアプリケーションのパフォーマンスを向上させるために使用されています。通常、ブラウザ上のDOMへの変更は上記のようなコストがかかるため、仮想DOMは変更を抽象化し、最小限のDOM操作に変換することで効率化を図ります。


## **仮想DOMの利点**



* パフォーマンス向上: 大量のDOM操作を最小限に抑えることで、ブラウザの負荷を減らし、アプリケーションのパフォーマンスを向上させます。
* 簡潔なコード: 仮想DOMの使用により、コードがシンプルになります。状態の変更に基づいてDOM操作を明示的に記述する必要がなくなります。
* クロスプラットフォーム: 仮想DOMはフレームワークやライブラリに依存せず、異なるプラットフォームや環境で利用することができます。


## **仮想DOMの弱点**



1. 追加のメモリ使用: 仮想DOMは、実際のDOMと同じ階層構造を持つデータ構造です。そのため、仮想DOMを使用することで追加のメモリ使用が発生します。特に大規模なアプリケーションでは、仮想DOMのメモリ使用量が増える可能性があります。
2. 初期レンダリングの遅延: 仮想DOMを使用する場合、初回のレンダリングには追加の処理時間がかかる場合があります。仮想DOMは実際のDOMとの比較が必要なため、初回のレンダリングは実際のDOMと同期するまでに時間がかかる場合があります。
3. パフォーマンスのオーバーヘッド: 仮想DOMは、実際のDOMとの比較や差分計算などの追加の処理を必要とします。これにより、一部の場合においてパフォーマンスのオーバーヘッドが発生する可能性があります。特に、高頻度で変更が行われる場合や、巨大なDOMツリーが存在する場合に影響が出ることがあります。
4. 複雑なコンポーネントの管理: 仮想DOMはコンポーネントベースのアプリケーションでよく使用されますが、複雑なコンポーネント階層の場合、仮想DOMの管理が困難になることがあります。コンポーネント間の状態の同期やパフォーマンスの最適化が課題となる場合があります。
5. 制御不能なDOM変更: 仮想DOMは、実際のDOMとの差分を計算して適用することでパフォーマンスを向上させますが、場合によっては意図しないDOMの変更が発生することがあります。特に、サードパーティのライブラリや外部のスクリプトが直接DOMを変更する場合に問題が発生することがあります。


## **Reactの仮想DOM**

Reactでは、仮想DOMを使用してUIの変更を追跡し、必要な最小限のDOM操作を行います。コンポーネントの状態が変更されると、Reactは仮想DOMを再構築し、以前の仮想DOMとの差分を計算します。その差分を実際のDOMに適用することで、必要な部分のみを更新します。

Reactの仮想DOMの手順は以下のようになります:



* コンポーネントの状態が変更されると、仮想DOMが再構築されます。
* 以前の仮想DOMと新しい仮想DOMの差分を計算します（この差分を仮想DOMの再調整と呼ぶこともあります）。
* 差分を実際のDOMに適用し、変更を反映します。

Reactの仮想DOMの利点は、状態の変更に応じて必要な部分のみを更新できることです。これにより、パフォーマンスが向上し、スムーズなユーザーエクスペリエンスが実現できます。


## **SvelteのDOM操作**

Svelteは、Reactとは異なるアプローチを取っています。Svelteでは、コンパイルする作業を行い、コンポーネント内のロジックとテンプレートが結合され、最終的にまとめられたVanilla JavaScriptのコードが生成されます。この生成されたコードには、仮想DOMの概念は存在しません。

Svelteでは、コンパイル時に変更をトラックし、直接最適なDOM操作を生成します。つまり、Svelteは実際のDOM操作を行い、仮想DOMを介さずに変更を反映します。これにより、実行時のオーバーヘッドが少なくなり、高速なアプリケーションが実現できます。

Svelteの利点は、ビルド時に最適化されたコードを生成し、実行時のオーバーヘッドを減らすことです。また、Svelteは必要な最小限のコードしか生成しないため、アプリケーションのサイズも小さくなります。


## **SvelteがReactよりも優れている点**



1. バンドルサイズの削減: Svelteは、コンパイル時にコンポーネントを効率的なJavaScriptコードに変換します。これにより、ランタイムでは仮想DOMのライブラリが必要なくなり、バンドルサイズが大幅に削減されます。Reactでは、仮想DOMのライブラリが必要であるため、バンドルサイズが大きくなる傾向があります。
2. パフォーマンスの向上: Svelteは、変更のあった部分のみを再レンダリングするため、効率的なUIの更新が可能です。また、Svelteはリアクティブなデータバインディングをサポートしており、状態の変更を自動的に検知して再レンダリングを行います。これにより、Reactよりも高速なパフォーマンスを実現することができます。
3. 学習コストの低さ: Svelteはシンプルな構文とコンセプトを持っており、学習コストが比較的低いと言われています。Reactはより複雑な構文やコンセプトを持っているため、初心者にとっては学習が難しい場合があります。Svelteは、HTMLやCSSとの親和性が高く、既存のWeb開発の知識を活かしやすいです。
4. ビルドタイムの最適化: Svelteのコンパイラは、コンポーネント内の未使用のコードやスタイルを自動的に除去する最適化を行います。これにより、ビルド後のアプリケーションのサイズやパフォーマンスが向上します。Reactでは、手動で最適化を行う必要があります。
5. フレームワークのサイズとパフォーマンス: Svelteは非常に軽量なフレームワークであり、そのサイズが小さいため、初期ロード時間が短くなります。また、Svelteはランタイムのオーバーヘッドが少ないため、実行時のパフォーマンスが向上します。


## **まとめ**



* React（やVue.js）では仮想DOMを使用し、コンポーネントの状態変更に応じて最小限のDOM操作を行います。差分計算により、必要な部分のみを更新します。
* Svelteでは仮想DOMの概念は存在せず、コンパイル時に最適化されたコードが生成されます。実際のDOM操作を行い、ビルド時の最適化と実行時の高速なパフォーマンスを実現します。




もちろん、フレームワークの完成度やコミュニティの大きさ、需要を理解したうえで選ぶことが大切どちらのフレームワークも優れた特徴を持っているので、プロジェクトの詳細や開発者の好みによって決めることになると思います。