Web Workersでエラー

JavaScriptで大量データを処理するとき、その実行速度が問題になることがある。FireFoxなんかだと「処理に時間がかかっています」というダイアログボックスが出ることがあるし、処理中は動作が遅くなってしまう(遅くなるのは現状ではやむを得ないのだが)。そこで並列処理を実装するのだがここで問題が発生した。

開発作業はFireFoxやSafariで動きを確認しつつ、だったのだが、たまたまChromeで見ることがあって「どんな感じかな」と思っていたら全く動いていない様子。「えっ」って感じ。

IEは確か次バージョン(10)で対応だった記憶はあるが、それ以外のブラウザなら際はあまりないんじゃなかったかなー、と腑に落ちなかった。で、コンソールを見たらやっぱりエラーが出ていた。

Uncaught Error: SECURITY_ERR: DOM Exception 18

例外が発生している。発生箇所はWeb Workersをコールしている場所だ。「対応してないわけないよな」と思い、しばらく調べてみたら原因がわかった。どうもローカル環境で使用すると例外エラーが発生するようだ(つまりURLが「file:///」で始まっている場合)。

同じファイルをサーバにアップロードし、HTTP経由でコールして正常に動作することを確認した。いろいろあるなー。

Firebugのバグ?「このページにはJavascript がありません」

JavaScriptで本格的にプログラミングしているならFirebugを活用している人は多いはずだ。しかし時々挙動不審・・・。

ある時突然「このページにはJavascript がありません」と怒られる時がある。「いやいやそんなことないって」「ソース見ればJavaScirptいっぱいあるじゃん」。しかし、いったんこのメッセージが出ると、リロードしようが何しようが「このページにはJavascript がありません」。

って実は、「何しようが」というのは間違い。例えばブラウザを一旦閉じて再度やり直すとうまくいく。原因は何かと調べたら。

一つのタブでFirebugを使っている最中に、別のタブを開いてFirebugを使おうとすると「このページにはJavascript がありません」と怒られるらしい。つまりFirebugでの作業は一つのタブでしか同時にできない、ということのようだ。

何とかならないものだろうか。

call

関数.call(オブジェクト[[, 引数1],引数2,…])

applyと似たような感じ。PHPでいうところのcall_user_func_arrayとcall_user_funcみたいな関係っぽい。

apply

関数.apply(オブジェクト[, 引数])

「関数」を実行するのだが、その際、「関数」内で使用する「this」を、「オブジェクト」で代用する、ということらしい。「関数」には「引数」を渡せるらしい(オプション)。

prototypeによる継承よりも簡便らしい。

JavaScriptでnewする、ということ

以下のスクリプトを基本に考える。

function Box(){}
var box=new Box;

Boxはまぎれもなく関数である。正確には関数オブジェクトというらしい(関数もオブジェクトである、という所以か)。コンストラクタですかね。

関数をnewして変数に代入すると、オブジェクトが生成される。それで出来たのがboxだ。通常boxはBoxから派生したのだからBoxで持っていた属性(というかフィールドというか)を引き継ぐ(ここでは何も持っていないので引き継いでいないけれど)。

newして出来たboxはオブジェクトになるわけだが、その際box.__proto__という属性を持つようになる(JavaScript内部でそのような処理が実行されているらしい)。box.__proto__に何が入っているかは後述する。

ここでプロトタイプというものを考える。プロトタイプは関数(ここでいうBox)に対して設定する(オブジェクトboxに設定するものではない)。たとえば上記のスクリプトに追記する。

function Box(){}
Box.prototype.size=1;
var box=new Box;

この状態でbox.sizeは1である。box.sizeは定義も代入もされたことはないけれど1になる。

関数オブジェクトがnewされると、できたオブジェクトに__proto__という属性ができるということは前述した。この__proto__には関数オブジェクトで定義されたプロトタイプ(これもオブジェクトなんだけど)を参照している(ポインタみたいな感じか)。

JavaScriptの仕様で、オブジェクトに特定の属性が存在しない時(ここでいうsize)、当該オブジェクトの属性である__proto__を走査し、sizeという属性を探す。ここでsizeが見つかると、当初のオブジェクトに、いかにもsize属性があるかのごとく、その__proto__.sizeの値を返す。これ、いわゆる継承ってやつですかね。

ちなみに上記のスクリプトで二行目と三行目をひっくり返してみる。

function Box(){}
var box=new Box;
Box.prototype.size=1;

二行目が実行された時点では、box.sizeはundefined。しかし三行目が実行されたらbox.size=1となる。これは__proto__に単純にコピーされたというのではなく参照で渡されているから。元の値が変化すれば、参照している側の値も変化する。

ちょっとわかってきた。


守谷市(まちの情報ポータル) 無料アンケートレンタルjpForm.net