Open6

QwikのDOM操作の速度とメモリ使用量

tomoamtomoam

前書き

話題を集めるQwikですが、そのパフォーマンスの焦点はTTIです。もちろんTTIは重要ですが、ユーザーは当然インタラクティブになったあとに操作をするので、その操作感もサクサクなのが重要です。

そしてメモリ使用量も少ない方が良いです。これは特にローエンドデバイスで顕著なのですが、メモリ使用量が多いとブラウザやデバイス自体の挙動が不安定になったりします。一般的に使用されているデバイスのシェアやスペックについては割愛しますが、興味がある方は以下をご参照ください。

ちなみにStatCounterで条件を絞って見てみると、例えばiOSでは、最新(iOS17)もしくは1つ前のiOSバージョン(iOS16)に追従できていないデバイスが徐々に増えてきていることがわかります。iPhoneで言えば7以前のユーザーが3割ほど存在する、という見方をすることもできます(さらに言うと1割はiPhone6s未満)。なのでこのあたりを日本国内のP75デバイス、P90デバイスとして見ると良いのかなと思います(GeekbenchのMulti-Core Scoreで大体900~1000くらい)。ちゃんと見るなら、Androidも加えて、もっと低いスペックを想定したほうが良いと思います。

tomoamtomoam

話が逸れたので元に戻します。そんなわけでサクサク動作の省メモリが望ましいわけですが、Qwikのその部分については未知数です。Qwikのドキュメントを見てもそのあたりには触れられていません。というわけで、ベンチマークを見てみようと思うわけですが、皆さんご存知の js-framework-benchmark にはQwikの実装がありません。これは困った。

それぞれのリポジトリを確認してみると、krausest/js-framework-benchmarkにも、BuilderIO/qwikにも、Qwikの実装を追加しようとしているissueがあります。

https://github.com/krausest/js-framework-benchmark/issues/1101
https://github.com/BuilderIO/qwik/issues/1404

どっちにもSolid.jsの作者のRyan Carniatoさんがいるの面白い。

Qwikとしてはこのベンチマークに対応するのは優先度は高くないけれど、コミュニティがやってくれるなら、という感じでしょうか。

tomoamtomoam

Qwikのissueには、Ryanさんが作った実装をベースにContributorの方が改善した実装へのリンクがあります。また、QwikのDiscordを見てみると、他の方の実装もありました。それぞれの実装を見て動かしてみたところ、以下のようなことがわかりました。

  1. https://github.com/literalpie/js-framework-benchmark/tree/qwik-literalpie
  2. https://github.com/BuilderIO/js-framework-benchmark/tree/add-qwik
  3. https://github.com/derkoe/js-framework-benchmark/tree/add-qwik

1の実装が一番良い結果が得られそうです。

tomoamtomoam

追記

2023/11/13に、js-framework-benchmark に Qwik の実装が入りました🎉
https://github.com/krausest/js-framework-benchmark/pull/1447

公式に入ったのでその結果を見れば良いかと思いましたが、まだ11/14時点でまだ結果は出ていないようです。
というわけで、せっかくなのでこの実装を使ってベンチマークを測定してみましょう。

tomoamtomoam

測定結果

注意

  • 冒頭に書いた通り、QwikはTTIに注力したフレームワークであり、js-framework-benchmarkのような操作速度などに注力したフレームワークではありません。そのため、Qwikにとって得意分野ではない部分のベンチマークとなります。
  • この計測は krausest/js-framework-benchmark が行ったものではなく、筆者が 11/14 に clone して筆者のローカルマシンで計測したものです。
    • ちなみに環境は MacBook Pro/CPU: M2 Pro/Memory: 32GB/OS: macOS Sonoma 14.1.1 です。
  • この計測結果はあくまで現時点のものであり、今後パフォーマンスは変化するものと思われます。

測定結果 - Duration

※vanillajsと主要なフレームワークの実装の計測結果も載せています
※左からパフォーマンスの良い順に並べています

これはDOM操作にかかる時間を測定するものです。
注意に書いた通り、やはりQwikはインタラクティブにDOMを操作するのは苦手なようで、Reactよりもパフォーマンスが悪いという結果です。
特に partial update のように一部分だけ更新する操作や、select row のような選択を切り替える操作があまり得意ではないように見受けられます。

なお、以下はQwikとは関係ない余談や個人の意見です。

  • Svelte(v5)がSolidのスコアを抜いていますが、このあたりは何回も実行していると抜きつ抜かれつ、みたいな感じです。
  • なお、Svelteは select row のテストで selector というAPIを使用していましたが、このAPIは.ベンチマークに特化しすぎているという理由で削除されました。js-framework-benchmarkの実装からも取り除かれる見込みです。そのためベンチマークは悪くなるはずです。
    • ちなみにSolidでは select row のテストで createSelector というAPIが使用されています。やはりこのベンチマークに特化しているものです。
    • この select row というテスト項目はこのように特化したAPIを用意することで比較的簡単にスコアを改善できるので、わざわざこのようなAPIを用意しているフレームワークは多い印象を受けます(特にパフォーマンスを謳っているフレームワークでは)。
  • Angularはv17でDOM操作のパフォーマンスが非常に改善されましたね。正直びっくり。Ivyに時間がかかる一方で、Jeffからの手紙のような内部のゴタゴタ、そしてMiško Hevery氏やIgor Miner氏などの黎明期からリードしてきたメンバーが抜け、正直厳しいのでは、と思っていましたが杞憂でした。これをやってのけたAngularチームに称賛を。
  • Reactは遅いけれど、swap rows だけでも改善したらもっと伸びそう。Angularより少し遅い、くらいまで持っていけそうな雰囲気がありますね。

測定結果 - Startup metrics

※vanillajsと主要なフレームワークの実装の計測結果も載せています
※左からパフォーマンスの良い順に並べています

Qwikの真骨頂ですね。vanillajsの実装より良いです。
しかもすごいのは、他のフレームワークは実際のアプリではもっとJavaScriptが増えるのでその分TTIが悪くなっていくのですが、Qwikはアプリが大きくなってもおそらくこのスコアを維持するであろうことです。
ただ留意すべき点は、このQwikの実装はQwik Cityが使われており、コミュニティによるQwik Cityを使用していない実装で計測したときはここまでのスコアではありませんでした。

再び余談や個人の意見:

  • ここでもAngularはReactを抜いています。v16ではReactより悪かったので、改善されていますね。ただ、DurationではVueにかなり近づいているものの、まだ開きがあります。今後こちらも改善されると良いですね。
  • Durationでもそうですが、VueとReactを比較するとかなり差があります。どちらも仮想DOMですが、中身は違うものなので「仮想DOM」という言葉では一括りにはできないということですね。

測定結果 - Memory allocation

※vanillajsと主要なフレームワークの実装の計測結果も載せています
※左からパフォーマンスの良い順に並べています

これはかなり予想外でした。Qwikのメモリ使用量が半端ない。
このメモリプレッシャーではローエンドデバイスで問題になりそうな気がする。
もしQwikを採用するなら、ターゲットとしている市場におけるP75デバイス、P90デバイスでQwikを(ちょこっと触るのではなく)いじり倒したほうが良さそうです。例えばECサイトアプリなら、そのページを開くだけではなくて検索したら商品の情報を細かくみたりカートに入れて決済してみたり、を何回何十回と繰り返してみると良いと思います(しかも、それを複数のタブで、別のアプリも複数立ち上げながら、です。ユーザーはアプリを複数同時に立ち上げながら、ブラウザアプリでは複数のタブを保持しているからです)。

また、このメモリ使用量が何に起因するのか気になりますねよ。おそらくその要因の1つには、このQwikの実装にはQwik Cityが使用されていることが挙げられます。他のフレームワークはメタフレームワークを使用していないのですが、QwikはStartup Metricsの項目で良いスコアを出すためにQwik Cityを使用しているので、その分モジュールをロードしているのだと思います。
ただ、コミュニティによるQwik Cityを使用していない実装でもMemory allocationのスコアはやはり良いものではありませんでした。それが今後改善されうるものなのか、それとも改善することができないのか。技術選定のリスク評価時に調査しておくと良いでしょう。

再び余談や個人の意見:

  • Solid、相変わらず素晴らしいパフォーマンス
  • Svelteはv4まではSolidと同じくらいでしたが、v5はメモリ使用量が増えましたね。この計測結果には載せていませんが、Solid-storeというSolidのもう1つの実装があり、それと同じくらいです。これはおそらく、Solid-storeで使用されているシグナルを利用したライブラリに相当する部分を、Svelteのランタイムが抱えていることに起因するのかなと推測します。
  • Vueは流石にそのランタイムのサイズがメモリ使用量に響いてきているようです。これがVaporモードでどうなっていくのか気になるところですね(SolidやSvelte 5と並びそう)。
  • Angular、ここでも改善されてますね。Reactを抜いています。Vueに迫ってきています。
  • Reactは変わらずファットですが、React Forgetによって改善されていくのか、RSCによって改善されていくのか(RSCの場合このベンチマークでは測れないだろうけど)、注目していきたいところです。

測定結果 - Transferred Size

※vanillajsと主要なフレームワークの実装の計測結果も載せています
※左からパフォーマンスの良い順に並べています

この指標自体かなり新しいもので、まだまだexperimentalなようなので参考程度ですね。スコアの算出も少し見直されると思います。

で、Qwikのスコア、これも予想外でした。Qwikのトータルのバンドルサイズは結構ファットなんですね。
ただ、Angularに比べれば半分くらい、Reactに比べれば4割程度なのでマシといえばマシなのかもしれません。
これも今後改善されうるものなのか、それとも改善することができないのか、技術選定のリスク評価時に調査しておくと良いでしょう。

再び余談や個人の意見:

  • Solid、本当にすごい
tomoamtomoam

QwikがTTIに特化しているのはよく知られていることですが、それ以外の項目のパフォーマンスについてjs-framework-benchmarkで見ていきました。
少なくとも現時点では、初期表示は得意だけれどインタラクティブな操作、動的なDOM変更については不得手なようです。そういった部分でユーザーにサクサクな動作をお届けしたいときには、個人的には第一候補ではありません。
ただし、もっと掘り下げていくと異なる結果になるのかもしれませんし、作るアプリケーションやターゲットの市場によって求められるパフォーマンスは変わります。実際の技術選定時にはもっとよく調査し、将来性やロードマップ、コードベースからリスクを評価し、適/不適を判断していくと良いと思います。