比較：無限リストパフォーマンス（素の JS、React、Mithril）

# はじめに

無限リストによるパフォーマンス検証テストを、Mithril でもやってみました。元記事はこちら。

- [Aerotwist - React + Performance = ?](https://aerotwist.com/blog/react-plus-performance-equals-what/)

fork したコードは以下にあります。Mithril の書き方がなっとらん！とかあれば、ご指摘下さい。

- https://github.com/t-suwa/samples/tree/gh-pages/perf/dom-react-vs-vanilla

とりあえず追試したい人は、以下から飛べます。

- [素の JS](http://t-suwa.github.io/samples/perf/dom-react-vs-vanilla/vanilla.html)
- [React v0.14.6](http://t-suwa.github.io/samples/perf/dom-react-vs-vanilla/react.html)
- [Mithril v0.2.2-rc1](http://t-suwa.github.io/samples/perf/dom-react-vs-vanilla/mithril.html)

# 環境

![スクリーンショット 2016-02-07 12.53.59.png](https://qiita-image-store.s3.amazonaws.com/0/65212/d50bb3ac-418c-d8fa-332b-481c281e6912.png)

Chrome は執筆時点の最新版で 48.0.2564.103 (64-bit) です。前回計測時からバージョンアップしているため、素の JS と React についても改めて計測し直しています。

さらに今回は、Android 端末でのテストも行いました。SIM フリーの [HUAWEI Ascent G6](http://consumer.huawei.com/jp/mobile-phones/tech-specs/g6-l22-jp.htm#anchor) です。CPU クアッドコア 1.2GHz、メモリ 1GB、Android 4.3 と、こちらもややレトロで非力な端末です。

G6 の Chrome は 48.0.2564.95 で、現時点での最新です。デスクトップ版とはバージョン番号が異なる理由はよくわからず。

願わくば、どなたか iPhone でテストした結果を共有してもらえたらなと。

# デスクトップ版

## 素の JS

![vanilla.png](https://qiita-image-store.s3.amazonaws.com/0/65212/e74021b8-1995-f6b2-ca15-e5d32b02f295.png)

傾向としては前回とほぼ同様です。100 枚から 400 枚にかけて描画時間が改善されているのは、おそらく V8 のオプティマイザの効果と思われます。

## React

![react.png](https://qiita-image-store.s3.amazonaws.com/0/65212/41c92b5f-1436-84bf-3302-2327b1acfe1b.png)

こちらも前回とほぼ同様ですね。素の JS と同じように、400 枚ぐらいまでは低く抑えられていて、そこから緩やかに上昇していきます。

## Mithril

Y 軸のスケールを見てもらえばわかる通り、React よりもやや劣ります。Mithril の方が React よりも速いかなと事前に予想していたのですが、見事にそれを裏切る結果となりました。

![mithril.png](https://qiita-image-store.s3.amazonaws.com/0/65212/79c2f089-f84f-401d-f491-f914f6107af6.png)

一方で、Total Time と JavaScript Time の差は React と同じようにほぼ一定を保っています。

## DOM 描画時間の比較

今回は、DOM 描画時間の平均についても比較してみました。Total Time から JavaScript Time を引いた値を平均化したものです。

|実装|平均 DOM 描画時間(ms)|
|:---|---:|
|素の JS|24.19|
|React v0.14.6|31.51|
|Mithril v0.2.2-rc.1|29.99|

React と Mithril は、どちらも素の JS に迫る健闘を見せています。素の JS が今回のパフォーマンステストのために DOM 描画をチューニングしていることを考えると、仮想 DOM による差分検出精度及び DOM 描画の最適化は、かなりの高水準に達していると言えそうです。

ただし、差分検出にかかるコストについては別の話なので、注意が必要です。いくら高水準でも、差分検出に時間をかけすぎているようでは本末転倒です。つまり、いかに短時間で差分検出を終わらせるかが、重要なポイントとなるわけです。

今回の無限リストのように DOM のノード数が単純に増加していくケースでは、素の JS がやっているように、追加されたデータだけを判別できれば簡単です。しかし、汎用的な差分検出ロジックにはそう言った前提を置くことができないため、毎回全データを比較することになり、結果として処理時間がかさむことになります。

なかなか厳しいですね（というか、元記事はそこをわかってこういうテストを用意している）。

## Total Time の比較

![totaltime.png](https://qiita-image-store.s3.amazonaws.com/0/65212/6d0fa3d0-1019-e188-0d32-66bad83dc1dc.png)

React は Mithril よりもやや良好なパフォーマンスを発揮しています。とは言え、今回テストを実施したややレトロな環境でこれしか差が観測されなかったということは、両者の性能はほぼ拮抗していると言って差し支えないと思います。

一方で、素の JS との差は歴然としています。仮想 DOM 実装は、素の JS と比較して、2〜3 倍程度遅い結果となっています。

# Android 版

Android については端末の遅さに我慢できず、1,000 枚までのテストとしています。ご了承ください。

## 素の JS

![vanilla-and.png](https://qiita-image-store.s3.amazonaws.com/0/65212/845584d7-87ef-65dc-d01e-0612207eb5bd.png)

600 枚時点のスパイクを無視すると、ほぼ安定したパフォーマンスです。傾向としては、デスクトップ版と同じです。

## React

![react-and.png](https://qiita-image-store.s3.amazonaws.com/0/65212/b5e45f9e-0257-a155-d1d0-3c0dbb686c65.png)

素の JS と比べると、かなり急な傾きで処理時間が増加していることがわかります。ここまで差があると、確実に体感できるレベルです。非力な端末なので、実装効率が如実に反映されやすいこともあると思います。

傾向としてはデスクトップ版と同じで、300 〜 400 枚ぐらいで底を打って上昇に転じます。ちょうど、スプーンを横から見たようなグラフです。

## Mithril

![mithril-and.png](https://qiita-image-store.s3.amazonaws.com/0/65212/4b1f97e5-1076-06bc-83a1-d4e51b8c328b.png)

こちらもデスクトップ版と傾向は同じです。不思議と React のようなスプーン型にはならず、素直な右肩上がりというところも共通しています。

## Total Time の比較

最後に、全体の比較がこちら。

![total-and.png](https://qiita-image-store.s3.amazonaws.com/0/65212/110d721b-ffa9-ddc7-c64b-39394f82c497.png)

React が Mithril よりやや速い傾向は、デスクトップ版と同じです。ですが、やはりその差はごくわずかです。

素の JS の安定度と比較すると、React と Mithril はどちらも処理時間が増加していく傾向にあり、デスクトップ版よりも傾きは急です。もっと枚数を増やせば、その傾向はさらに強まるでしょう。

# まとめ

無限リストを使って、素の JS、React、Mithril のパフォーマンスを計測しました。その結果、

- React は Mithril よりもやや速い傾向にある
- 仮想 DOM による差分検出精度は、チューニングされたコードに肉薄している
- 素の JS と比較して、仮想 DOM 実装は 2〜3 倍程度遅くなる（あるいはそれ以上）
- 非力な端末では仮想 DOM の差分検出コストは無視できないレベル

ということがわかりました。

Mithril がやや遅いというのが意外でしたが、全体としてはほぼ予想通りで、個人的には納得。パフォーマンス測定シリーズは、ひとまずこれにて終了です。

また気になるフレームワークが出てきたら、テストしたいと思います。