MessagePack-JS (3)
cuzic です。
前回の投稿は ベンチマークテストにバグがあって、うまく処理できていなかったようです。ベンチマークテストのバグを修正すると、私の実装は eval に比べて 10倍以上遅いということが分かりました。
今日は一日かけて MessagePack のバイナリ文字列を Internet Explorer 環境で高速に処理する方法について、模索していました。
Internet Explorer 環境の特徴としては、以下の点があります。
- 単純に JavaScript エンジンが遅い
- responseText ではバイナリ文字列が処理できない。( FireFox 等のような overrideMimeType によるハックが使えない)
- responseBody でバイト配列を返す
- バイト配列は、 JavaScript では直接扱えない。
- バイト配列の処理には JavaScript 以外の技術の利用が必須(VBScript の利用、XMLDOM の COM オブジェクトの利用など)
バイト配列の処理手法として当初は VBScript の利用による解決を模索したのですが、次の問題点を克服できませんでした。
- メモリ使用量が非常に大きくなり、スタックオーバーフローが発生する場合さえある
- 耐え難く遅い。(上記と同根の問題?)
そこで、現時点で github にコミットしているコードでは次の方式を採用しました。
- Microsoft.XMLDOM の COM オブジェクトを利用して、一旦 base64 エンコードする
- base64 エンコードした文字列を JavaScript で書いたデコード処理で 0〜255 までの数の配列に変換
- 2で得た配列を元に MessagePack の形式として解釈
いろいろ実験した中ではこの方式が IE8 環境でもっとも高速に動作するように思われました。
base64 へのエンコード処理は、Microsoft.XMLDOM を利用することで、
function binary_to_string(binary){ var xmldom = new ActiveXObject("Microsoft.XMLDOM"); var bin = xmldom.createElement("bin"); bin.dataType = "bin.base64"; bin.nodeTypedValue = binary; return bin.text; // base64 文字列 }
と簡単にできます。
base64 デコードについては、http://www.webtoolkit.info/javascript-base64.html を参考にしつつ、独自に実装しました。
あと、Microsoft.XMLDOM ではなく ADODB.Stream を使って、バイナリ文字列を扱う手法についても見当したのですが、私の InternetExplorer のセキュリティ設定では利用できない COM オブェジェクトであったため、採用しませんでした。