この記事は福岡若手Sier_bc Advent Calendar 2019の11日目の記事です。
はじめに
今回は仮想DOMについて書いてみました。
- フロントエンドに興味のある方
- 仮想DOMについて知りたい方
を対象にしています。
そもそもDOMって何よ?
「Document Object Model」の略ですが、Wikipedia先生の説明では
DOMは、HTML文書やXML文書(あるいはより単純なマークアップされた文章など)をオブジェクトの木構造モデルで表現することで、ドキュメントをプログラムから操作・利用することを可能にする仕組みである。Documentの種類、操作に用いるプログラミング言語の種類に依存しない仕様である。
要するに、
HTMLを構築する木構造データのことだよ!プログラミング言語で操作できるよ!
ってことです。ここで注意しなければならないのは、MDNの説明にも
(前略)ふつうは JavaScript を使用しますが、 HTML、 SVG、 XML などの文書をオブジェクトとしてモデリングすることは JavaScript 言語の一部ではありません。
とあるように、
DOMはJavascriptを用いて操作することができるけど、Javascriptの一部じゃない
ってことです。さらに、__WebブラウザはDOMからHTMLを解析してWebページをレンダリング__します。
本記事では仮想DOMと区別して、通常のDOMを__リアルDOM__と呼称します。
じゃあ仮想DOMって何よ
正体は__Javascriptのオブジェクト__です。
JavascriptのオブジェクトでリアルDOMを仮想的に作って、
- 仮想DOMを二つ用意
- 一方の仮想DOMをJavascriptで操作(一般的にリアルDOMを操作するより速い)
- 変更前後の仮想DOMの差分を比較
- 差分だけをリアルDOMに反映
- 反映されたリアルDOMをブラウザがレンダリング
ということで最終的にリアルDOMを操作するのですが、通常、リアルDOMを操作する場合は__リアルDOMが変更されるたびにブラウザがHTMLを解析してレンダリングする__のでコストが高いです。
仮想DOMを使うメリットはレンダリングコストを低くできることの他に、
- UIとロジックを分離できる
- 状態の管理を簡略化できる
- UIとロジックを繋ぐ処理が簡単になる
です。
じゃあどう変わるのか見てみようじゃないの
- リアルDOMを操作する場合
- 仮想DOMをVue.jsを使って操作する場合
を見てみましょう。
リアルDOMを操作する場合
こちらを参考にさせていただきました。
<div id="app">
<p id="counter">0</p>
<button type="button" id="increment">+1</button>
</div>
<script>
const state = { count: 0 };
const btn = document.getElementById('increment');
btn.addEventListener('click', () => {
const counter = document.getElementById('counter');
counter.innerText = ++state.count;
})
</script>
リンク先にもありますが、このコードを見ると
- stateというオブジェクトで現在のcountを管理しよう
- ボタンをクリックしたらインクリメント処理を行おう
- state.countをインクリメントしよう
- state.countを表示するために表示する要素(p#counter)を取得しよう
- 取得した要素の文字をstate.countで更新しよう
と考えると思います。まぁこれでもいいんですけど、
- いちいち要素をJavascriptで取得してるからUIとロジックが混在
- HTMLにもJavascriptにも状態の初期値が記載
- UIとロジックを結びつけるためにわざわざリスナーを定義してる
っていうのがめんどくさいですね。
仮想DOMをVue.jsを使って操作する場合
こんな感じのコードになるかと思います。
<template>
<div>
<p>{{ count }}</p>
<button v-on:click="increment">+1</button>
</div>
</template>
<script>
new Vue({
data: {
count: 0
},
methods: {
increment: function() {
this.count += 1
}
}
})
</script>
ね?
- JavascriptでHTMLの要素を取得しないからUIとロジックが分離
- 状態の初期値はJavascript側で完結
- リスナー代わりのv-onディレクティブがHTML側に記載されてるからUIとロジックを繋ぐ処理が簡略化
されているでしょう。これが仮想DOMを使うメリットです。
あれ?結果的にレンダリングコストは変わるん?
一応色々とベンチマークはあるようなのですが、フレームワークによって得意不得意がある模様です。
まとめ
以上で、仮想DOMの説明をしてみました。仮想DOMは確かにレンダリングコストを低減する画期的なものですが、やはり開発する上ではUIとロジックが分離されるという点も非常に強力で、生産性向上に寄与するものだと思います。
謝辞
今回の記事について、様々な記事にお世話になりました。
この場をお借りしてお礼申し上げます。