lit-html / hyperhtml / React のパフォーマンス
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ hyperhtml が速いけど lit-html とほぼ同じ
◆ 複雑なものだと lit-html のほうが速かった
◆ React はこの中だと一番遅いけど 思ったよりは速かった
◆ 複雑なものだと lit-html のほうが速かった
◆ React はこの中だと一番遅いけど 思ったよりは速かった
そういえば lit-html と hyperhtml で速度比較をしたことがない気がします
予想だと hyperhtml のほうが最適化頑張ってそうなので速そうです
ついでに似たような感じで使える React も合わせて比較してみました
比較部分は DOM の変更の更新処理のみです
コンポーネントはそれぞれ違いなどが大きいので扱いません
React では setState による更新は非同期になってしまうので ReactDOM.render を呼び出して同期的にます
React
lit-html
hyperhtml
結果は
変更がない場合は 予想通り hyperhtml が最速でした
ただ lit-html もほぼ違いがないくらいです
この 2 つは新しい値が前回の値と比べて違ったら その箇所の DOM を直接更新するだけで ツリー全体の比較とかしないので速いです
React の場合は JSX や createElement で作ったオブジェクトでツリー全体を比較することになるので遅めです
ループ変数の i を 2 で割ったあまりの 0 か 1 を h1 のテキストにします
0 と 1 は交互に変わるので毎回更新処理が起きます
変更点の measure 関数だけ書きます
更新なしに比べると どれもだいたい倍くらいの時間です
DOM 要素の作成と交換の時間分です
id や class の属性 イベントリスナ 繰り返しも入れます
テンプレートの書き方は違いますが 同じ HTML になるものなので hyperhtml 版のみ書きます
以外にも hyperhtml が一番遅いという結果になりました
wire も使ってるのでありえるとすればイベントリスナを毎回付け替えるところな気がします
lit-html の場合はリスナは同じで参照呼び出しする関数を切り替えてるだけという最適化がされてるので
イベントリスナの設定をやめてみた場合も試してみるとだいたいこれくらいでした
React よりは速くなってますが これまでの誤差と違って明確に lit-html のほうが速いです
これは変更なしでやってますが 上で変更のありなしで試した場合に 変更ありのほうが時間はかかるものの どれも同じくらいに増えていたので 変更ありにしても順位は同じになると思います
となると lit-html よりは hyperhtml のほうが速いと思ってましたが 複雑になると lit-html のほうが速いようです
予想だと hyperhtml のほうが最適化頑張ってそうなので速そうです
ついでに似たような感じで使える React も合わせて比較してみました
比較部分は DOM の変更の更新処理のみです
コンポーネントはそれぞれ違いなどが大きいので扱いません
React では setState による更新は非同期になってしまうので ReactDOM.render を呼び出して同期的にます
同じテキスト 10000 回
同じテキストへの更新を 1 万回行いますReact
<!doctype html>
<script src="https://unpkg.com/react@16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js" crossorigin></script>
<div id="root"></div>
<script type="module">
const root = document.getElementById("root")
const e = React.createElement
const update = value => ReactDOM.render(e("h1", {}, value), root)
update("abc")
const measure = () => {
console.time("")
for(let i=0;i<10000;i++) {
update("ABCDEFGHIJKLM")
}
console.timeEnd("")
}
measure()
measure()
measure()
</script>
lit-html
<!doctype html>
<div id="root"></div>
<script type="module">
import { html, render} from "https://unpkg.com/lit-html?module"
const root = document.getElementById("root")
const update = value => render(html`<h1>${value}</h1>`, root)
update("abc")
const measure = () => {
console.time("")
for(let i=0;i<10000;i++) {
update("ABCDEFGHIJKLM")
}
console.timeEnd("")
}
measure()
measure()
measure()
</script>
hyperhtml
<!doctype html>
<script src="https://unpkg.com/hyperhtml"></script>
<div id="root"></div>
<script type="module">
const { bind, wire } = hyperHTML
const root = document.getElementById("root")
const update = value => bind(root)`<h1>${value}</h1>`
update("abc")
const measure = () => {
console.time("")
for(let i=0;i<10000;i++) {
update("ABCDEFGHIJKLM")
}
console.timeEnd("")
}
measure()
measure()
measure()
</script>
結果は
R
92.69482421875ms
15.60498046875ms
13.8759765625ms
L
26.526123046875ms
2.46484375ms
1.371337890625ms
H
14.2470703125ms
2.6640625ms
1.024169921875ms
変更がない場合は 予想通り hyperhtml が最速でした
ただ lit-html もほぼ違いがないくらいです
この 2 つは新しい値が前回の値と比べて違ったら その箇所の DOM を直接更新するだけで ツリー全体の比較とかしないので速いです
React の場合は JSX や createElement で作ったオブジェクトでツリー全体を比較することになるので遅めです
変化ありテキスト 10000 回
次は変化ありにしてみますループ変数の i を 2 で割ったあまりの 0 か 1 を h1 のテキストにします
0 と 1 は交互に変わるので毎回更新処理が起きます
変更点の measure 関数だけ書きます
const measure = () => {
console.time("")
for(let i=0;i<10000;i++) {
update(String(i % 2))
}
console.timeEnd("")
}
R
124.0458984375ms
31.545166015625ms
30.02099609375ms
L
27.7099609375ms
3.899169921875ms
4.448974609375ms
H
17.218017578125ms
4.17919921875ms
4.467041015625ms
更新なしに比べると どれもだいたい倍くらいの時間です
DOM 要素の作成と交換の時間分です
複雑なの 1000 回
少し複雑めの HTML にしてみますid や class の属性 イベントリスナ 繰り返しも入れます
テンプレートの書き方は違いますが 同じ HTML になるものなので hyperhtml 版のみ書きます
const update = v => bind(root)`<div id=${v.id}>${v.a}${v.b}${v.c}${v.a}${v.b}${v.c}<ul class=${v.cls}>${v.items.map(x => wire(x)`<li onclick=${() => console.log(x)}>${x.name}</li>`)}</ul></div>`
const data = { id: "abc", a: "123", b: "234", c: "345", cls: "def", items: [] }
for (let i = 0; i < 300; i++) data.items.push({ name: String(i) })
update(data)
const measure = () => {
console.time("")
for (let i = 0; i < 1000; i++) {
update(data)
}
console.timeEnd("")
}
R
243.291015625ms
214.063232421875ms
208.973876953125ms
L
80.671142578125ms
57.93408203125ms
54.1591796875ms
H
714.5029296875ms
716.552001953125ms
711.27783203125ms
以外にも hyperhtml が一番遅いという結果になりました
wire も使ってるのでありえるとすればイベントリスナを毎回付け替えるところな気がします
lit-html の場合はリスナは同じで参照呼び出しする関数を切り替えてるだけという最適化がされてるので
イベントリスナの設定をやめてみた場合も試してみるとだいたいこれくらいでした
R 110
L 33
H 87
React よりは速くなってますが これまでの誤差と違って明確に lit-html のほうが速いです
これは変更なしでやってますが 上で変更のありなしで試した場合に 変更ありのほうが時間はかかるものの どれも同じくらいに増えていたので 変更ありにしても順位は同じになると思います
となると lit-html よりは hyperhtml のほうが速いと思ってましたが 複雑になると lit-html のほうが速いようです