JavaScript is not enabled on browser.
[Reference]developer.mozilla.org
項目 WebWorkers有無で共通化する仕様
worker
宣言のURL
main script内で宣言する外部script(for_url.js)のURLは
index.htmlからの相対pathで記述する

self.worker = new Worker("js/for_url.js");

なお、main内の関数をcreateObjectURLで指定する方法は
次に示すimportScriptsを使用しないcaseに限られる
worker
外部script
共通化する処理jobを別のscript(for_importScripts.js)に定義してimportする
importするscriptのpathは外部script(for_url.js)からの相対pathで記述する
importするscriptが複数ある場合、comma区切りで読み込み順に並べる(配列渡し不可)
これより外部scriptは最も単純に次のように記述される

importScripts("for_importScripts.js");

onmessage = function(e){
  postMessage(My_entry.job_imported(e.data));
};

e.dataがmainから受け取るcopy-data(参照を持たないJSON形式)
なお、外部scriptに変更を加えた場合、
"cacheの消去とhard再読込み"をしないと反映されないcaseがあるので留意する
worker
同時並列化
threadを同時並列化する場合、同時並列数self.n_threadのWorkerを宣言する

  for(var i=0; i<self.n_thread; ++i){
    self.workers[i] = new Worker(self.url);
  }

なお、overheadとthroughputのtrade-offに応じて最適なn_threadを選択する
通常、memory sizeが問題にならない場合、最適なn_thread=CPU-core数*(1~2)
main/worker
共通化するjob定義
mainとworkerそれぞれでimportする共通のscriptにjobを定義する

My_entry.job_imported = function(_data){
  var out = null;
  var isWorker = (typeof window === "undefined");
  try{
    out = Math[_data.sw_job](_data.in);
  }
  catch(e){
    out = e.message;
    out += (isWorker)? "@worker": "@main";
    throw new Error(out);
  }
  _data.out = out;
  return _data;
};

mainから受け取ったdataを処理した後、同様のdataを返却する
いずれかのerror発生場所を特定するためにwindow objectの存在可否を判定する
なお、workerからはmainのwindowやdocumentにaccessできないことに留意する
そのため、ここで定義するjobは並列化向きのmedia処理や数値計算が一般的と考えられる
main
依頼処理
mainからworkerにまとめてarr_dataを渡すhandler_workerを用意し、排他処理を実施する
最も上流の実行命令直後とhandler_worker.runを呼ぶ関数の最初にlock判定を加える

My_entry.original_worker.prototype.run_worker = function(arr_data_in, useWorker){
  var self = this;
  if(self.handler_worker && self.handler_worker.isLocked) return false;
  arr_data_in.forEach(function(data_in, i){
    if(typeof data_in.i === "undefined"){
      data_in.i = i;
    }
  });
  self.arr_data_in = arr_data_in;
  self.arr_data_out = [];
  if(self.handler_worker && useWorker){
    self.init_worker();
    self.handler_worker.run(self.arr_data_in);
  }
  else{
    self.arr_data_in.forEach(function(data_in){
      try{
        self.callbacks_worker.onmessage({data: self.job_worker(data_in)});
      }
      catch(e){
        self.callbacks_worker.onerror(e);
      }
    });
  }
  return self;
};

追加依頼を受けないlock状態にすることで最大thread数に制限を設ける
さらに、threadの終了処理を確実に実施してからlock状態を解除する
なお、後述する再初期化処理init_workerをhandler_worker.runの直前に実施する
他方、WebWorkers非対応の環境ではSingle-threadで実行する
共通化したjob_importedであるself.job_workerをforEachで順番に実行し、
後述する受取り処理self.callbacks_worker.onmessageに返却dataを渡す
同様にerrorをcatchして後述するerror処理self.callbacks_worker.onerrorに渡す
handler_worker
実行処理
上記のhandler_worker.runの関数を以下に示す

My_entry.handler_worker.prototype.run = function(arr_data){
  var self = this;
  if(!(self.hasWorker) || self.isLocked) return false;
  self.isLocked = true;
  arr_data.forEach(function(data, i){
    var worker = self.workers[i%self.n_thread];
    if(worker){  // check null
      worker.postMessage(data);
    }
  });
  return self;
};

WebWorkers非対応||lock状態の場合、即座にfalseを返却する
それ以外の場合、lock後、同時並列化したworkerの中断terminateを判定をしながら
postMessageで外部scriptに繰り返しdataを送信する
なお、繰り返しnew Workerを宣言する必要はないことに留意する
また、postMessage後のerror処理の伝播はworkerをterminateしても中断できないため、
構文error等は事前に弾いてrunを実行しない方が望ましい
main
受取り処理
error処理
workerに登録する受取り処理とerror処理のcallbackをmain内に定義する

My_entry.original_worker.prototype.set_callbacks_worker = function(){
  var self = this;
  self.callbacks_worker.onmessage = function(e){
    var self = this;
    var data = e.data;
    self.arr_data_out[data.i] = data;
    var len_in = self.arr_data_in.length;
    var len_out = Object.keys(self.arr_data_out).length;
    if(len_out === len_in){
      self.stop_worker();
    }
    return self;
  };
  self.callbacks_worker.onerror = function(e){
    var self = this;
    self.stop_worker(true);
    return self;
  };
  return self;
};

workerからはmain依頼順とは順不同にdataが返却されるため、
依頼順data.iに結果が並ぶように配列に代入してarr_data_out[data.i] = data
Object.keys(self.arr_data_out).lengthが
依頼したdataの長さself.arr_data_in.lengthに一致すれば終了判定する
また、終了処理を実施する
error発生時や中断時、body.onbeforeunload時も同様の終了処理を実施する
error発生時、上記の配列を初期化するself.stop_worker(true)
なお、callbackは別のscopeから呼ばれるため、thisをinstance selfでbindする
元のcallbackを不変の前提で直接bindする場合、再代入が必要であることに留意する
callback = callback.bind(self);
handler_worker
中断・終了処理
handler_workerの中断・終了処理の関数を以下に示す

My_entry.handler_worker.prototype.terminate = function(){
  var self = this;
  self.workers.forEach(function(worker){
    if(worker){
      worker.terminate();
    }
  });
  self.workers = [];
  self.isLocked = false;
  return self;
};

worker.terminateをcallして全threadを強制終了する
また、memoryを解放するself.workers = []
さらに、lock状態を解除する
なお、workerをteminateした時点で再利用不可のため、
再利用する場合、必要になった時点でself.workersを再宣言する
main
中断・終了処理
上記のhandler_worker.terminateをcallするmainの中断・終了処理を以下に示す

My_entry.original_worker.prototype.stop_worker = function(isClear){
  var self = this;
  if(self.handler_worker){
    if(self.handler_worker.isLocked){
      if(self.callbacks_worker.final){
        self.callbacks_worker.final();
      }
    }
    self.handler_worker.terminate();
  }
  if(isClear){
    self.init_arr_worker();
  }
  return self;
};

なお、terminate直前にlock判定して中断log表示等を1回のみ実施する
main
再初期化処理
mainの再初期化処理を以下に示す

My_entry.original_worker.prototype.init_worker = function(){
  var self = this;
  if(self.handler_worker){
    self.handler_worker.terminate();
    self.handler_worker.re_init();
  }
  else if(window.Worker){
    self.set_job_worker();
    self.set_url_worker();
    self.callbacks_worker = {};
    self.set_callbacks_worker();
    self.entry.$.bind_objs(self, self.callbacks_worker);
    self.handler_worker = new self.constructors.handler_worker(self.url_worker, self.callbacks_worker);
    self.init_arr_worker();
  }
  return self;
};

self.workersを再宣言するhandler_worker.re_init直前に再度terminateを実施する
なお、new Workerが重複宣言されないように留意する
try~catch処理
Ver.1.82.15追加
擬似codeを以下に示す

My_entry.prototype.main = function(){
  var self = this;
  var callback = function(){
    try{
      if(self.isLocked) return false;
      self.isLocked = true;
      self.run();
      self.isLocked = false;
    }
    catch(e){
      self.isLocked = false;
      throw e;
    }
  };
  setTimeout(callback, 50);
  return self;
};

main処理の上流でcatchしてerror処理をswitchする(原則、多用しない)
非同期処理の場合、callbackの中に記述する
なお、lock処理も同様に完結させる(別の処理からflagを操作しない)