Google Chromeは速くないって
Google Chromeが速いという意見をよく耳にしますが、何を言っているのかさっぱりわかりません。そういう人たちはGoogleのマーケティング戦略に騙されすぎです。
ブラウザの速さを決めるのはたくさんの要素がありますが、Chromeが速い理由の一つにJavascriptエンジンであるV8が速いことが挙がっています。本当にそうでしょうか。
まず理論面から。
多くのWebアプリケーションで、Javascriptがボトルネックになるとすれば、その大半はDOM操作によるものです。そしてDOM操作はレンダリングエンジンが実装していて、Javascriptはそれらを呼び出しているにすぎません。ChromeのレンダリングエンジンはSafariと同じWebkitです。ということは、速度の大半を決めるレンダリングエンジンが同じ以上、Chromeが爆速だというのは迷信です。ちなみにFirefoxのJSエンジンであるSpiderMonkeyをTraceMonkeyに入れ替えるという話の中でも、実際の問題の多くはGeckoにあることが知られてきています。
つまり、数値計算による物理シミュレーションをリアルタイムで行うならまだしも、Web/Javascriptでは言語自体の実装が速くなっても大きな変化はないということです。
次に実験。
Firefox3/Safari3/Chromeに対して以下のような実験を行います。
1.一つの変数に繰り返しかけ算を行う
2.ドキュメントに繰り返しDOMノードを追加する
3.あるオブジェクトのプロパティに繰り返しアクセスする
4.配列に数値をため込み、join("")で文字列にする
結果は以下のとおりです。
test1(かけ算) | test2(DOM操作) | test3(プロパティアクセス) | test4(文字列生成) | |
Firefox | 84 | 257 | 93 | 75 |
Safari | 109 | 31 | 140 | 62 |
Chrome | 8 | 113 | 12 | 55 |
予想通り、Chromeは純粋な演算(test1)とプロパティアクセス(test3)には滅法強そうです。ただし、DOM操作(test2)はSafariより遅く、文字列生成も他とあまり変わらず。DOM操作がSafariより格段に遅いのには驚かされます。
結論。
パフォーマンスチューニングにおける大事なことは、ボトルネックを見極めて局所的につぶしていくことですが、残念ながらV8の設計者はただの速度バカだったようです。一画面でJavascriptを数千行書いている自分に言わせれば、クライアントサイドのJavascriptはDOM操作と文字列生成がほとんどです。足し算やかけ算がいくら速くなってもアプリが速くなることはありません。
まとめ。
Chromeは本当に速いのか?をJavascriptの側面から理論と実験で考察しました。タイトルは釣りですが、Googleのマーケティングにやられている人たちを見る度に嘆かわしくなるのでちょっと纏めてみました。本当はJavascriptだけでなくレンダリングやネットワーク戦略(ダウンロード、DNS他)等もブラウザの速さに大きく寄与する部分ですが、とりあえずJavascriptは速くないということがわかっていただけたと思います。むしろChromeの速さのはレンダリング部分であって、その実体Webkitはすごいので、みんなSafariを使うべき!
おまけ。
テスト内容を載せておきます。
<html> <head> <script type="text/javascript"> function time(){ return (new Date()).getTime(); } function test1(){ var t0 = time(); var n = 1000000; var res = 0; for(var i=0; i<n; i++){ res *= (i+1); } alert(time() - t0); } function test2(){ var t0 = time(); var n = 10000; for(var i=0; i<n; i++){ document.body.appendChild(document.createElement("div")); } alert(time() - t0); } function test3(){ var t0 = time(); var n = 1000000; var obj = {a: 1, b: 2}; for(var i=0; i<n; i++){ var tmp = obj.a + obj.b; } alert(time() - t0); } function test4(){ var t0 = time(); var n = 100000; var buf = []; for(var i=0; i<n; i++){ buf.push(i); } var result = buf.join(""); alert(time() - t0); } </script> </head> <body> <input type="button" value="test1" onclick="test1()"> <input type="button" value="test2" onclick="test2()"> <input type="button" value="test3" onclick="test3()"> <input type="button" value="test4" onclick="test4()"> </body> </html>