重たいUIライブラリ ― 2007年08月31日 03時16分47秒
Zend入門も書かずにJSネタ。ごめんなさい。がんばります。
UIライブラリの選定
いまかかってる仕事で、フォームの入力支援なんかで多少リッチなUIを使いたかったのでライブラリを検討していた。スクラッチしてるヒマはなさそうだからな。クライアント側で若干のデータ操作なんかもやりたいのでprototype.jsを使うことを基本にして、UIライブラリもその延長線上での検討となった。
もともと入力支援より以前にちょっとだけエフェクトを使いたかったのでscript.aculo.usも試してみようと思っていたところ、ちょうどprototype.js + script.aculo.us なリッチUIライブラリが見つかった。それがspinelzだ。
デモを見たところ、そこそこUIはそろっていて見た目もそんなに悪くなく、なによりprototype.jsとのコンフリクトを気にしなくてよい(あたりまえだが)ため、導入してみることにした。
まぁ、入れては見たものの
最初に使ってみたのが郵便番号の部分検索で複数候補がある場合のモーダルダイアログに適用してみた。あまり苦労せず使えたので「なかなかよいかも」と思っていた(デザインのカスタマイズはめんどくさそう。画像とCSS両方だからな)。
次に日付入力で、おあつらえ向きに「DatePicker」が用意されているので試してみた。
残念ながら、というか、表示位置はクラスに食わせる要素を直接制御する必要があり、また座標算出系のヘルパーもないため、prototype.jsのPositionとか使いながら自前で位置合わせを行うことになってなんだかなぁ、という感じ。
さらに月や年単位で前後に移動できるのだが、なんとなくもっさりしている。いや、そんなレベルではなく3呼吸くらい待たされる感じだった。それでも「まぁ、なんとか使えるかな」と甘いことを考えていた。
ただ、他のページに比べて、DatePickerを導入しているページの表示が、コンテンツがロードされてから少し待たされるのが気になってはいたのだが...
使い方が悪いっちゃそうなんだけど
おととい手がけてた部分が、入力フォーム中に日付入力が8つ(!)もあり、バカ正直にそれぞれに対して1つづつDatePickerをバインドしてみた。ページロード完了が相変わらず重いが、まぁとりあえずできたし良しとしよう。
ところが、他のJS部分の動作確認やレイアウトの確認のためIEで確認(普段はFirefoxでのみ確認してる)してみたら、ページロードがこれでもかってなくらい重たい。もー重たい。どうにも重たい。
さすがにこれは実用にならんと思ってボトルネックを調べたところ、どうもDatePickerのコンストラクタ(というかinitialize)からの一連の流れが原因だった模様。
もう少しマシな実装してよ...
コードを追っかけていったところ、初期化や表示月の変更など表示内容を更新する必要がある局面で、すべて新しくDOMノードの構築を行っているという、かなりひどい実装になっていた。なるほど月を前後するときに重たいワケだ。
DOM操作でtableを構築するのはDHTMLの中でもかなりの高コストなのだが、配置した要素を使いまわすことなく愚直に再構築するとは、とてもUIライブラリとして公開しているシロモノの実装とは思えない。
重たいのはIEとFirefoxで、OperaやSafariといった比較的「軽量」と呼ばれるブラウザは実用に耐える速度だったのだが、これらはいかんせんマイナー路線。一番利用者が多いであろうIEで実用的な速度がでないのでは問題だ。
Firebugのプロファイリングで一番ボトルネックになっているメソッドを見つけ出し、外部からオーバーライドして(こういうときJSってステキと思う。継承なしでオーバーライドできちゃうんだもん)、40~50%くらいの改善が見られた(それでもサクサクとはいかない)のだが、今度はなぜかOperaで動作が不安定になった。むぅ。
結局スクラッチすることに
少し悩んだ挙句、多少他の部分の進捗状況が良いことを口実に自分でスクラッチすることにした。午後から6時間ほどかかり切りでなんとか使えるものができたが、いやーUIライブラリは面倒くさいわ。今回の業務向けと割り切って、テーマだなんだと見た目の部分はあまり手をかけてないがそれでもこんだけ時間がかかる。いや、多分dara-jの手が遅いだけなんだけども。このくらい2~3時間でさくっとできるスキルがほしい。
文句たれてるだけじゃ生産性がないので、ちょっとしたコネタをば。(つか、常識?)
今回の日付選択コントロールみたいにポップアップして何かを選択するようなインターフェイスの場合、関係ない部分をクリックしたら閉じるようにするのにどうやってイベント拾ってきたらいいのか良くわからなかったんだけど、documentってonclickがあるのね。
ポップアップさせた要素(と関連する要素)のonclickだけイベントバブリングをキャンセルすれば、それ以外の、ウィンドウ中のあらゆる場所のクリックイベントをdocument.onclickに集約できるので、ポップアップさせた要素を閉じさせるイベントをadd/attachすればよかったのか。思ったより簡単。
以下、サンプル。ここではポップアップトリガのボタンとポップアップ要素自身のクリックイベントの場合のみEvent.stop()をしている。
<html> <head> <style type="text/css"> div#panel { width : 100px; height: 100px; border: solid 1px dimgray; color : dimgray; } </style> <!-- prototype.jsが必要ね --> <script type="text/javascript" src="prototype.js"></script> </head> <body> <button id="test">test</button> <hr> <div id="panel" style="display: none"> </div> </body> <script> (function() { // button#test Event.observe( $("test"), "click", function(evt) { Element.show( $("panel") ); Event.stop( evt ); } ); // div#panel Event.observe( $("panel"), "click", function(evt) { Event.stop( evt ); } ); // document Event.observe( document, "click", function(evt) { Element.hide( $("panel") ); } ); })(); </script> </html>
まとめ
- spinelzのDatePickerは重たいぞ。もっとがんばれ。
- document.onclickってイベント拾えるんだ。
- Firebugのプロファイリング機能、めっさ便利(いまさら)
- もっとブラウザ向けのスクリプト書いとけ > 俺
コメント
_ 木下 ― 2007年09月01日 01時16分21秒
_ dara-j ― 2007年09月01日 02時24分12秒
まさか開発者ご本人からコメントをいただけるとは思っていませんでした。悪口みたいなエントリになってしまい、大変恐縮です。
> 現在開発段階ではありますが、全体的にかなりパフォーマンス改善されております。
> 表示内容の変更や、複数Datepickerをバインドしてもストレスなくご利用いただけると思います。
>
> またご指摘の座標位置についても、オプションを追加してクリックされた位置に表示できるようにしました。
おお、いろいろと改善されておられるのですね。
Datepickerについては自作のものがなんとか泣きながら使えるレベルまでになってきた(除:Safari。原因調べなきゃ...)かな、と思っているのですが、svnにあがってるほうもためさせていただきます。
それにしても自分でスクラッチしてみて、UIライブラリの開発の大変さを改めて思い知らされました...
大変でしょうけど、がんばってください。
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※なお、送られたコメントはブログの管理者が確認するまで公開されません。
トラックバック
このエントリのトラックバックURL: http://dara-j.asablo.jp/blog/2007/08/31/1760605/tb
※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。
貴重なご意見、ありがとうございます。
現在のSpinelzはかなり重く、使いづらいと思います。
申し訳ございません。
現在開発段階ではありますが、全体的にかなりパフォーマンス改善されております。
表示内容の変更や、複数Datepickerをバインドしてもストレスなくご利用いただけると思います。
またご指摘の座標位置についても、オプションを追加してクリックされた位置に表示できるようにしました。
まだリリースはしておりませんが、姉妹プロジェクトのRubricksの正式版にバンドルされており、リリースバージョンと比べて動作が不安定ということはないと思います。
なるべく早く公開したいと思っておりますが、もしよろしかったらこちらをお試しいただればと思います。
svn://dev.rubricks.org/var/svn/rubricks/spinelz/trunk
オプションや、複数バインドする場合の使い方は、ドキュメントをご参照ください。
http://dev.rubricks.org/wiki/RubricksDevelopmentSpinelzDatePickerJa