Angularの新しいレンダリングエンジンで採用された "incremental-dom" とは何なのか
どうやら,Angularの新しいレンダリングエンジンであるIvyには,incremental-dom という技術が採用されているらしい.incremental-domとは一体どういった技術なのだろうか.
incremental-domとは,Googleが発表したWebアプリケーションにおけるレンダリングのための技術である.
incremental-dom | An in-place DOM diffing library
この記事では,incremental-domの仕組み,Reactで採用されている手法である「仮想DOM」との違いや利点について解説する.
また,デモとして実際にincremental-domを実装し,簡単なTODOリストアプリが動作することも確認した.その実装は下記レポジトリで確認できる.
https://github.com/musou1500/toy-idom
仮想DOMにおけるレンダリング
incremental-domと似たような技術に,仮想DOMというのがある.仮想DOMは,以下のような手順でレンダリングを行う.
- DOMの木構造を模したプレーンなJavaScriptオブジェクト(仮想DOM)をUIの状態として持っておく
- DOMを更新する必要が生じた時,仮想DOMを生成する関数を呼び出し,新しい仮想DOMを得る
- 新しいものと古いものを比較し,DOM APIを直接使用することなく,どの部分を更新すれば良いかを判断する
- 比較した結果に応じて,DOMを更新する.
これが仮想DOMにおけるレンダリングの仕組みである.
仮想DOMを使用することで,DOM APIを直接使用せずに変更箇所を特定することができるため,DOM APIを使用する箇所は少なく済み,より良いレンダリングのパフォーマンスが得られる.
加えて,アプリケーションの開発者がどのように差分を検出し,DOMを更新するのかについて考える必要がなくなる.
incremental-domにおけるレンダリング
では,incremental-domどのようにレンダリングが行われるのか.以下にincremental-domにおけるレンダリングの流れを示す.
- 仮想DOMと同様,DOMの木構造を模したPOJOを持っておく(仮にこれを「状態オブジェクト」とする)
- DOMを更新する必要が生じた時,レンダリング関数を呼び出す
- レンダリング関数は,incremental node functionと呼ばれる関数を呼び出す
- incremental node functionは,状態オブジェクトを参照し,更新の必要がある部分を判断し,DOM APIでそれを適用する
これが incremental-domにおけるレンダリングの仕組みである.
仮想DOMとは,以下の点において異なる.
- 比較のために新しい状態オブジェクトが生成されない
- レンダリング関数内で呼び出されたincremental node functionがインクリメンタルにDOMの更新を行う
例えば,仮想DOMを使用するとき,以下のような仮想DOMを返す関数があったとする.
function render(state) {
return (
<div>Helo {state.name}</div>
);
}
仮想DOMでは,UIを更新する必要が生じると,
この関数が都度呼び出され,古い仮想DOMとの比較によって差分検出が行われ,DOMに更新が適用される.
incremental-domにおいては,同様のUIをレンダリングする関数は以下のようになるだろう.
function render(state) {
elementOpen('div');
text(`Hello ${state.name}`);
elementClose('div');
}
ここで,レンダリング関数が何か値を返すのではなく,単に関数を呼び出していることに着目してほしい.
この,elementOpen
,text
,elementClose
が,incremental node functionである.
最初にレンダリングを行う際,以下のような状態オブジェクトが生成されたとする.
{
"name": "div",
"children": ["Hello world"]
}
ここで,状態が変更され, "Hello world" が "Hello musou1500" に変更されたとする.
そうすると,以下のようにDOMの更新が行われる.
- レンダリング関数が呼び出される
-
elementOpen
が呼び出される - 状態オブジェクトを参照.引数で渡された
div
と比較.更新の必要なしと判断 -
text
がよびだされる - 状態オブジェクトを参照.引数で渡された
Hello musou1500
と比較.更新の必要ありと判断 - DOM APIを呼び出し,
div
タグ内のテキストを書き換え
このようになる.
デモ
incremental-domを理解するため,自分で簡単な実装を書き,それを使ってTODOアプリを動かしてみた.
https://github.com/musou1500/toy-idom
今後,時間が出来たときにでも,パーティクルを表示させるものを作るなどして,
仮想DOMとのパフォーマンス比較をやってみたいと考えている.
incremental-domの利点
incremental-domを使用することの利点として
- 比較のために新しい状態オブジェクトが生成されないため,レンダリング時のメモリ割り当てを減らすことができ,パフォーマンスが予測可能となる
- テンプレートベースのアプローチに容易にマップする
ということが挙げられる.
なお,仮想DOMに比べて書きづらそうに見えるが,incremental-domは直接使用されるというよりは,
フレームワークなどから利用されることを意図している.
Angularが独自のテンプレート構文を持っていることを考えると,Ivyはそのケースだと言えそうだ.
この記事は,私がGitHubに投稿した incremental-domとは何なのか を試験的にZennに公開しているものです.
Discussion