ecl.js (Escape Codec Library) と Sleipnir の相性が悪い件について

とあるサイトで ecl.js を使っています。ecl.js とは JavaScript で文字コード変換を行うライブラリで Escape Codec Library が正式名称です。配布元は Escape Codec Library: ecl.js です。ちなみに yaplog に組み込まれている /blog/js/urlEnDecoding.js も元ネタは ecl.js みたいですね。もちろん Sleipnir で yaplog 見ると激遅です・・・

Shift_JISエンコードやEUC-JPエンコードなども可能な escape エンコード・デコード関数のライブラリ
文字列をすべてのコンピュータで読めるような形式に変換したり、変換されたものを元の文字列にデコードすることができる関数のライブラリです。
ビルトイン関数 escape() , unescape() とは異なり、どの種類のブラウザでも同じ変換結果が得られます。
JISコード変換テーブルを搭載し、従来JavaScriptでは実現が困難であった、Shift_JISコードやEUC-JPコードなどの文字コードとしてのエンコード・デコードも可能となっています。なお、この変換テーブルには、直接漢字は記述せず、Unicode 番号を圧縮したデータをASCIIコードの文字で記述しているので、任意の文字コードで使えるという特徴があります。
Internet Explorer 5.0以上、Netscape 7、Operaなどで使用可能です。

さてこの ecl.js ですが、どうも僕が愛用している Sleipnir と相性がめちゃくちゃ悪いようです。ecl.js が組み込まれていると数秒間フリーズしたかのような状況になります。というのをたまたま他の情報を探していたときに
Sleipnirで50タブくらい開いている状態でEscape Codec Library: ecl.jsを使用しているサイトにアクセスすると激しく重くなる件 - 文殊堂
で見つけました。

遅い原因をちょっと調べてみて不具合が発生しないように改良を加えてみました。

- スポンサーリンク -

まず処理が思い場所は JCT11280 文字列を生成する無名関数部分です。JCT11280 文字列には何が入っているかは ecl.js のページに説明がありまして

JIS規格(JIS X 0208-1997)に取り込まれている文字に加えて、Windowsで使用できる○付き数字やiモードの絵文字領域の文字(Shift_JIS および Unicode 系のコードで使用可能)なども加えた11280文字(未定義領域も含む)が、JISコード順で代入されています。
これを生成する関数は、11280文字分のUnicode 番号を差分圧縮して、ASCIIコードの文字のみを使って符号化したデータとデコードプログラムからなり、ファイル読み込み時に実行されて、元の文字を生成するようになっています。この仕組みにより、11280文字を記述するのに必要なバイト数の半分近くにまでサイズが縮小され、そして漢字等が直接記述されていないので、任意の文字コードで使用することが可能となります。
また、</ といったブラウザを混乱させるおそれのある文字列も含まれていないので、HTMLファイルに直接この生成関数を記述することも可能です。

です。11280文字のJIS漢字を JavaScript が load されたときに動的に生成しているわけです。でもって Sleipnir で遅くなる理由はその生成アルゴリズムにあるわけです。文字生成プログラムの後半部分を見やすく展開すると

c=34,i=2,p,s="",u=String.fromCharCode,t=u(12539);
while(++c<127)C[u(c)]=c^39&&c^92?i++:0;
i=0;
while(0<=(c=C[a.charAt(i++)]))if(16==c)if((c=C[a.charAt(i++)])<87){if(86==c)c=1879;
while(c--)s+=u(++p)}else s+=s.substr(8272,360);
else if(c<86)s+=u(p+=c<51?c-16:(c-55)*92+C[a.charAt(i++)]);
else if((c=((c-86)*92+C[a.charAt(i++)])*92+C[a.charAt(i++)])<49152)s+=u(p=c<40960?c:c|57344);
else{c&=511;
while(c--)s+=t;
p=12539}return s')();

となっています。文字列を生成する毎に + 演算子を使って文字列を結合しています。この方法は、JavaScript の要素追加・変更で innetHTML と DOM の速度検証に書いたように + 演算子を使って文字列を結合すると IE 系でパフォーマンスが劣化します。そして理由は不明ですが Sleipnir では更に超絶パフォーマンスが劣化するようです。
したがって文字列の結合を配列 + join 方式に変更してみました。

c=34,i=2,p,s=[],u=String.fromCharCode,t=u(12539);
while(++c<127)C[u(c)]=c^39&&c^92?i++:0;
i=0;
while(0<=(c=C[a.charAt(i++)]))if(16==c)if((c=C[a.charAt(i++)])<87){if(86==c)c=1879;
while(c--)s.push(u(++p))}else s.push(s.join("").substr(8272,360));
else if(c<86)s.push(u(p+=c<51?c-16:(c-55)*92+C[a.charAt(i++)]));
else if((c=((c-86)*92+C[a.charAt(i++)])*92+C[a.charAt(i++)])<49152)s.push(u(p=c<40960?c:c|57344));
else{c&=511;
while(c--)s.push(t);
p=12539}return s.join("")')();

テストプラグラムを作成してパフォーマンス測定してみました。

  Sleipnir ie6 firefox2 opera9 safari3 for win
ecl オリジナル 10781 ms 141 ms 94 ms 63 ms 31 ms
ecl 高速化版 78 ms 62 ms 94 ms 62 ms 31 ms

というわけで Sleipnir でのパフォーマンスが改善されフリーズ状態にならなくなることが確認できました。その他のブラウザでの速度も影響はなさそうです。

改良版 ecl.js はこちらからダウンロードできます。ecl_new.js(右クリックで保存してください。)

パフォーマンステストはこちらをクリックしてください。

- スポンサーリンク -