HTML.jsについて

HTML.jsというJavaScriptで楽にDOM操作を行えるようにするライブラリーがあります。結論から申しますと、このライブラリーは絶対に使うべきではないライブラリーとなっています。

この記事は執筆時点の最新バージョンであるHTML.js 0.9.3を元にして書いており、今後なんらかの変更がHTML.jsに加えられることによって、次に書く内容は陳腐化してしまう可能性はないわけではありません。ですが、ひとまづこの記事を執筆している時点では使うにあたって不都合ばかりが多く発生してしまう非常に邪悪なライブラリーです。

HTML.jsはMutationObserverを使えるウェブブラウザーではMutationObserverを用いて、MutationObserverが使えない環境ではDOMSubtreeModifiedイベントを用いてHTML文書の変更を検知しています。そしてHTML文書に変更のあったつどに任意の処理を発生させています。そしてその処理は変更が起きた要素の数だけ行われます。そのためにHTML文書の変更が頻繁に起きるようなウェブページの場合には動作が緩慢になってしまうおそれがあります。

また、それだけではなくHTML.jsは本番環境で使用するにあたって致命的なまでの仕様上の問題があります。任意の要素をHTML.jsの提供するAPIを用いて取得するとその取得した要素のDOMノードには本来存在し得ないメソッドやプロパティーを勝手に追加してしまいます。このような行為はJavaScriptの仕様上、できるようになっているものではありますが、既存のオブジェクトに、後に実行されたものが外部から変更を加えるような動作は、あまりにも行儀が悪い行為だというのがわたしの認識です。また行儀が悪いだけではなく、別の動作によってなにかしらの競合が発生してしまうおそれも同時に存在することとなります。あきらかな悪手をやってのけているのが、このHTML.jsというライブラリーになります。

先にも書いた通りにこの記事はHTML.js 0.9.3の内容を元に書いており、後に変更が加えられることによって健全化がなされる可能性は否定しません。ですがHTML.jsはDOMContentLoadedDOMSubtreeModifiedイベント、HTMLElement.prototype.matchesSelectorメソッドが存在しなければまともな動作をしてくれないようになっています。それにより、FAQにもあるように、よほど新しいウェブブラウザーでしか動作しないようになっています。古いウェブブラウザーを無視できるのであれば、そもそもこのようにDOM操作の実行を代りに行ってくれるようなライブラリーは本来不要なのです。DOM操作の実行を代りに行ってもらう必要があるのは、古いIEのように他のウェブブラウザーと動作に違いが存在してしまうウェブブラウザーのためだけです。

古いウェブブラウザーを無視できるのであれば、このようなライブラリーを使うことによって得られるものは記述の簡素化だけです。ですが、得られるものが乏しいだけではなく、動作速度の低下を招いてしまったり、依存関係の発生による動作確認の手順が増えてしまうなどといった不都合が複数あります。それでもあなたはわざわざこのような邪悪なライブラリーを使い続けますか?

JavaScriptは決して遅くない

数年前ならいざ知らず、現代のJavaScriptは充分に高速な動作が実現されている。無論C言語で記載されたいわゆるネイティブアプリケーションと比較すれば計算速度等では大きく劣ってしまう。だがしかし複雑な計算等を必要としない通常範囲のアプリケーションであればJavaScript (とHTMLとCSS) で記述がなされたアプリケーションの実行速度はネイティブアプリケーションと遜色ないものになると半ば強い確信を抱いている。ではJavaScriptで記述がなされているアプリケーションの動作が緩慢であるという認識がなぜ多くの場でなされているのか。それは単純な理由である、そのアプリケーションの作者が知識不足でDOM操作が冗長的なものとなっており無駄が多くなってしまっているからだ。

JavaScriptの動作が速くなろうとも、DOM操作は現在でも多くの場面で遅くなってしまっている。document.getElementsByTagNamedocument.getElementsByClassName などで取得することとなる HTMLCollection オブジェクトや NodeList オブジェクトはその仕様上、取得後であってもHTML文書が変更されるごとにその内容の更新が行われており、内部的に常に処理を実行させ続ける必要がある。そのために濫用激しければ致命的なまでの速度低下を招いてしまう。これはHTML文書に含まれる要素が増えれば増えるほどに顕著なものとなってしまう。Array.prototype.slice.call(document.getElementsByTagName('a')) のようなかたちにして HTMLCollection オブジェクトや NodeList オブジェクトから Array オブジェクトへと形を変容させることによってある程度の改善を計れる。このほかにもDOM関連の処理は簡単に動作を遅くさせてしまうものばかりであり、安易な使用は自身の首を締めるだけの結果となってしまう。

先の段落で記載した HTMLCollection オブジェクトや NodeList オブジェクトを Array オブジェクトへと変換させるのと同種のことはjQueryの内部でも行われてあり、その結果として雑に書かれたスクリプトであればjQueryを使用しているものの方が高速に動作することとなってしまっている。jQueryは読み込み時に互換性確保のために通常は不要となる処理を多く実行させており、非常に動作が遅い。jQueryが速いのではなく、自身の書き方に問題があるのだと、初めに正しく自認することが肝要となっている。

ではどのような記述が速度向上には有効であるのか。これは難しい問題である。かくいう私自身も方法を未だに正しく確立できていない。一先はDOM操作を省略させていくのが安定した方法ではなかろうかと考える。JavaScriptを用いて任意の要素に対し style 属性の値を一つ一つのプロパティーを与えるような処理は避け、スタイルシートに任意のクラスを設定した上でプロパティーを事前に記載しておき、JavaScriptを用いて行うのは任意の要素に対する class 属性の値を変更するのみに留めておくのが速度の面で考えれば優秀なのではないだろうか。またアニメーションを行わせる場合についても同様である。動きが起こるつどに動的に任意の要素に対して位置情報に関する値を一つ一つ追加していくのは、速度の著しい低下を招き、アニメーションが汚らしく見えてしまう恐れもあるだろう。こちらも先の対処と同様に class 属性値のみを変化させ、アニメーション自体はスタイルシートに transition プロパティーや animation プロパティーを用いた記載を行う。これによりある程度のアニメーションであれば問題なく扱えるのではないかと推測する。もちろんそれだけでは対処できない事案もあるだろう。適材適所に思案し、適切なコードの記述を行う必要があるのだろう。

また任意のノードを取得するには無論相応の処理時間がかかってしまう。複数回の処理が行われることが明白であるのであれば、任意のノード取得後に適切な変数へ格納することが当然のことではあるが重要となるだろう。この点は基礎的なことであろうとは思うのだが抑えられていないコードは現在にも未だ多く目にする。特にjQueryに依存したコードでは顕著である。jQueryの内部的に簡易的なキャッシュがなされているとはいえ、あまりにも迂闊であると言わざるをえない。

加えてインターネット上に限られた情報しかなく、使用方法をつかむのに多少の手間はいるだろうが、DOM RangeDocumentFragmentインターフェースを使うのも有効であろう。特にDOM Rangeは操作するHTML文書のノードが多ければ多いほどに顕著なまでの速度向上が見込める。先の記載の通りにインターネット上には限られた情報しかないが、W3Cの仕様に書かれている以上の動作はしない。なのでウェブブラウザーでの動作を確認しつつ、幾通りかの記述を実際に行ってみれば、既にある程度のDOM操作を行えるようになっている人物であれば習得は難しくないのではないだろうか。必ずしも要るという場面は極めて稀であろうが、知識として有しておいて損はないだろう。

繰り返しになるが現在のJavaScriptは遅くない。古くは並列処理ができなかった。だが現在はWeb Workersを用いることにより並列処理を行えるようになっている。Web Workersはこの記事を執筆している時点ではまだ勧告候補の段階ではあるが、現時点でも多くのウェブブラウザーで安定して動作するようになっている。使うにあたって心配する点はない。正しく気を遣いさえすればネイティブアプリケーションに遜色ないアプリケーションをJavaScriptを用いて作れる。なにを心配する必要があろうか。

SPDYはどのような状況でも速度向上が見込めるような万能な技術ではない

ここ最近、俄かにSPDYが流行の兆しを見せているように見える。言及されぬ技術は使われず、そして使われぬ技術は存在しない物であるのと同義であると私は考えるので悪い事ではないのだが、本来SPDYを使う上で注意すべきである点を無視して言及しているように見えるので一度深く熟考する必要があるのではないだろうか。

SPDYは複数の要求を一つの接続に纏め上げられる通信規格であり、通常のHTTPによる通信に於いて存在していた大きな速度遅延の要因をなくす事は、確かに出来ている。だがSPDYは規格の仕様上、TLSを上層に配す、HTTPSである事を求められている。HTTPSは暗号化と複合化の処理だけではなく、証明書の確認も行われる事になる為に、HTTPよりも速度は低下する事になってしまっている。数十程度の接続しかなされないようなウェブページであれば、SPDYを使う事によって得られる速度向上よりも、HTTPSを使う事による速度低下の方が大きくなり、結果として速度が低下してしまう事になる。SPDYによる恩恵が得られるのは、画像が数百枚も貼付されているウェブページや、Ajaxによる動的な情報取得を繰り返し短時間の内に幾つもの通信が常に発生し続けるようなウェブアプリケーションに限られると私は考える。文書が主体となり、画像が数枚しかないようなウェブページでは全く意味のないどころか、逆に悪影響を与える結果にしかならないのではないか。

また、同一のホスト名による通信でなければ、SPDYによる速度向上の恩恵には与れない。厳密に言えば、同一の証明書に於いてエイリアスの指定を行ったり、コモンネームにワイルドカードを使用したりする事により、複数ホスト名を使う事が出来る。だが、ホスト名が限定されてしまう事には変わりない。例えば、Amazon S3といったストレージサービスを使い、画像ファイル等の配信を行っている場合に、SPDYは全く効果を発揮しない。またAmazon S3では任意のホスト名を指定する事が出来るが、現時点ではホスト名が s3.amazonaws.com や *.s3.amazonaws.com となっていない場合にはHTTPのみになってしまっている。Amazon側に証明書を渡す事によりこうした問題が発生しなくなる可能性はあるのだろうが、現時点では問題しかない。

そして、SPDYはHTTPSでの通信となっている事が必須である都合上、今までHTTPで提供されていた場合にはURIが変わってしまう。301 Moved PermanentlyとLocationヘッダーを用いた転送を行う事により、既存のURIから誘導する事は可能であるが、クールなURIは変わらないというウェブの基本的な考えが通用しなくなってしまう。かてて加えて、もしいつかSPDYを使うのを止めようと考えた時にも、今度はHTTPSを常に維持し続けなければならなくなる。HTTPの維持はそう面倒な事ではないが、HTTPSの維持は証明書の絡みもあり、多少とはいえ煩わしさがある。今後の事を考えれば、必ずしも必要であると断定出来ない場合には避けるべきであろう。

現在多く使われているウェブサーバーはApacheとnginxの二つだろう。Apacheにはモジュールが存在しており、またnginxには開発版に任意のパッチを適用した上でビルドする事により、いづれの場合にも簡単にSPDY対応を施す事が出来る。その為に他の速度向上の方法を試す前に気軽にSPDYを使おうと考える者もいるであろう。だが、SPDYによって速度が向上する場合は非常に限定的である。きちんと自身の提供する物がどういった物であるのかを考え、SPDYが適切でない場合には、適切な他の手段を使用するべきである。

例えばWordPressを使用している場合はPHP自身の速度の遅さやMySQLを用いた情報の授受によって生じる速度低下の方が通信によるボトルネックよりも致命的であると考えられる。APCの導入やmemcached等を使った適切なキャッシュを行う方が速度向上には有効だろう。またJavaScriptによる動的な操作を多様するようなウェブページであればDOM操作を適切に行う事により、処理が遅くなってしまう事が避けられ、閲覧者の体感する速度向上は非常に大きくなる。現在のJavaScriptは多くの実装がJITにより高速に動作するようになったが、DOM操作は非常に遅いままである。適切な記述をしなければ、その積み重ねにより無視出来ない致命的な速度遅延を招く。SPDYを使うよりも有効で、そして現実的な方法が幾つも存在している。

とはいえ、機密性の高い情報のやり取りを行う必要があり、元よりHTTPで提供する事が考えられず、HTTPSにする必要がある場合にはSPDYを使っても損はない。SPDYに限らず、こうした最新の技術は深く考えた上で適材適所に合致するような適切な選択をそのつどに行っていくのが肝要である。

iOS 6.0にアップデートしてSafariのデバッグコンソールが使えなくなってしまったので代替方法を考えた

iPhoneとiPadのシステムソフトウェアをiOS 6.0にアップデートしたところ、Safariのデバッグコンソールを表示する方法を見付けられなくなってしまった。Webインスペクタというのが追加され、Mac OS X上で動作するSafariがあれば効率良くデバッグ出来るようになったようなのだが、非常に残念な事に現在の私の手許にはMac OS Xの環境が存在しない。なのでiOSのSafariでのデバッグが出来ないようになってしまった。探せば既存のデバッグコンソールを表示する方法があるのかも知れないが、しばらく探しても見付ける事が出来なかったので、非常にその場凌ぎの解決法で済ませた。

<script type="text/javascript">
window.addEventListener('error', function(error) {
var result = document.getElementById('result') || (function() {
var result = document.createElement('pre');
result.setAttribute('id', 'result');
document.getElementsByTagName('body')[0].appendChild(result);
return result;
})();
var message = [error.filename, '@', error.lineno, ': ', error.message].join('');
result.textContent += '\n' + message;
return false;
});
</script>

このような記述をHTML文書に出現する全てのscript要素よりも前に加える事で、エラーが発生した際にエラーの表示がページの最下部にされるようになる。

ただWebインスペクタは非常に便利そうである。調べれば調べる程に羨しくなる。早急にMac OS X環境を得たい。しかし、だが、しかし……。

HTML 5は「アメリカ人」が標準化させようとしている物ではありません

内容に関しても思う所は御座いますが、一つだけ。

HTML 5の仕様を現在 書いていらっしゃるGoogle社のIan Hickson氏はアメリカの方ではなくスイスで生まれた方です。現在どちらに住まれているのかは存じませんが少なくとも「アメリカ人」と表現されるような方ではないかと考えます。

またHTML 5は当初はApple社、Google社、Mozillaが共同で設立させた団体であるWHATWGによって仕様が策定されていましたが、現在ではW3Cに移管されています。W3Cは多国籍な団体 (そもそもイギリスで生まれ方が創設した団体です) であり、日本で生まれた方も多く議論に参加なさっています。そもそもApple社もGoogle社も元より多国籍な会社であり、アメリカで生まれた方 以外も多く所属されているように思います。

そしてその仕様策定の為の議論もWHATWG管轄下の時から一貫して、開かれたメーリングリスト上で行われています。もちろんその議論には日本で生まれたと思われる方も多く参加なされています。

まだワーキングドラフトで仕様が完全に固まり切っていないHTML 5という仕様を無理矢理勝手に使おうとして、各実装の仕様準拠度のバラつきを以って、仕様自体を、仕様を策定されている方方を批難し、否定するような方が現れてしまうのは非常に残念な事であると思います。