Web workers を使うと、JavaScriptでもマルチスレッドが使えるのですが…

これは使いにくい。

何が使いにくいって、Workerの指定がスクリプトではなくファイルなこと。

そのうえ Same Origin Policy の対象。data: URLも「外様」扱いなのでだめ。

というわけで、こんな workaround を考えてみました。

こんなJSを用意した上で…

http://blog.livedoor.jp/dankogai/js/workaround.js

こうします。

worker = new Worker('http://blog.livedoor.jp/dankogai/js/workaround.js');
worker.msgdom= document.getElementById('result');
worker.onmessage = function(event) {
  worker.msgdom.innerHTML = '' + event.data;
};
worker.onerror = function(error) {
  console.log(error);
};

var work = function(){
  var max = 1e6;
  var primes = [2];
  var is_prime = function(n){
    for (var i = 0; i < primes.length; i++){
      var d = primes[i];
      if (d * d > n)  break;
      if (n % d == 0) return 0;
    }
    primes.push(n);
    return n;
  };
  for (i = 2; i <= max; i++) if(is_prime(i)) postMessage(i);
};

worker.postMessage('' + work);

とりあえず素数を100万まで探索させています。Safariではあっという魔に終わりますが、Firefoxでは結構かかります。途中で飽きたらterminateしてください。setTimeout()なしでもアニメーションできるのは本当に楽ですね。

functionを直接渡さず、文字列として渡しているところがポイントです。それをevalせずにfunction()を取り除いた上でnew Function()しているのは、こうしないと動かないから。変なの。

この回避策、FirefoxとSafariではうまく行くのですが、Chromeでは

chrome-dom-exception-18

となります。つれないですね。

Enjoy!

Dan the Blog Worker

追記:Chromeでも今見たら動きますね。localでやると駄目なだけ?

追^2記:Mobile SafariにはWorkerオブジェクト自体ありませんね。ま、当然か。