Web Workカー応用に関する一つの考えと実現


この文章は以前CUでは人気が足りなくて、ここに送り直しました.へへへ
 
        会社の製品はバックエンドで一回のセッションの状態を維持する必要がありますが、ユーザーがブラウザを閉じる時、即時に資源を釈放する必要があります.これは以前はブラウザwindowのロードとunloadイベントを通じて、それぞれCancel Close ActionとStartClose Actionをトリガして実現しました.その後、ブラウザを殺すプロセス、ネットワークの異常などの場合、バックグラウンドはブラウザの状態を確認できなくなり、リソースを即時に解放できなくなりました.だから、もう一つの製品では、「ときめき」監視技術を使って、フロントエンドタイミング(例えば15~30秒)を使って、後ろ側に心臓の鼓動を送ります.バックエンドが特定の時間に動悸が取れないなら、ブラウザが閉まっていると思います.この時、このセッションのすべてのリソースを回収することができます.一般的には、このメカニズムは動作可能ですが、いくつかのcaseは先端Javascriptの演算量が非常に大きいかもしれません.いつもこの時、私達は多くJavascriptがマルチスレッドであることを望んでいます.
1、パッケージWeb Workerの構想
       
    
ネット上の无数のコピーを见て回っていますが、実际の内容は同じウェブワーカーについて绍介した后に、ウェブワーカーは本当に多スレッドであることが分かりました.しかし、このような簡単なpostMessageとonmessageの例を見ていると、どうやって使うべきか分かりません.どうやって想像の中の「ときめき」スレッドを実現しますか?
       
    また、ブラウザの互換性の問題については、IE、悪質IEが独自にWeb Workerをサポートしていません.どうすればいいですか?良いメッセージは、IE 8から開始され、フレーム間でpostMessageとonmessageを介して通信されたことをサポートするIEが開始され、これは少なくとも1つのWeb WorkerをシミュレートするAPIレベルで可能性を提供することができる.
       
    Javaのjava.lang.Threadはもう非常に良いスレッド応用モデルです.ウェブワーカーをjava.lang.Threadに包装したらどうなりますか?少なくともJavaプログラマーにとっては使いやすいと思います.たとえば:
// 1、      ,     java.lang.Runnable 
var task = {
    context: { x:1 }, //        
      
    run: function(){ //  context       
        this.context.x++;
        //         post  
    } 
};
  
// 2、      
var myThread = new js.lang.Thread(task);
 
// 3、       onmessage  
myThead.onmessage = function(e){ //              
 
    //         this.stop(); 
};
  
// 4、    
myThread.start();
  
// 5、                  
myThread.submitTask(task);
    
以上のjs.lang.Threadの構想から見れば、包装後のWeb Workerはマルチスレッド計算にとても使いやすいはずです.Threadは計算能力を提供していますが、データと計算方法はコーディネーターによって決められます.
2、Webワーカーはどのように作業するべきですか?
       
    第1歩の構想の下で、Web Worketはjs.lang.Threadにカプセル化されます.そうすると、task、RunnableはWorkカーに送らなければなりません.Workカーのコードはこのように見えるはずです.
  // onmessage     
  var _onmessage = function(e){
      
      /*
       *     e.data          var thi$ ...  }   string
       *
       * var thi$ = {
       *
       *     context: {}, //     
       *
       *     run : function(){
       *         //     
       *     }
       * } 
       */ 
       
      eval(e.data); //     
  
      //   ,      thi$  ,    
      thi$.run(); //  thi$.run.call(thi$);
    
  };
3、実験的なjs.lang.Threadを実現する.
    
Javaプログラマまたは着ています
以前の文章を読んだ人は、大体次のThreadの実現が分かります.もちろんJ$VMやjs.lag.lassなど私のオープンソースの項目があります.興味があれば、行けます.
Googleコード
ちょっと見てください
/**
 * The <code>Thread</code> for easily using Web Worker, and for the
 * IE8/9 use a iframe simulate Web Worker
 * 
 * Runnable :{
 *     context: xxx,
 *     run : function
 * }
 * 
 */
js.lang.Thread = function(Runnable){
    
    var worker, runnable;

    var _onmessage = function(e){
        var evt = e.getData(), data;
        if(evt.source == self) return;
                
        try{
            data = JSON.parse(evt.data);
        } catch (x) {
            data = evt.data;
        }
        
        if(js.lang.Class.typeOf(data) == "array"){
            // [msgId, msgData, [recvs], null, pri]
            switch(data[0]){
            case "console_inf":
                J$VM.System.out.println(data[1]);
                break;
            case "console_err":
                J$VM.System.err.println(data[1]);
                break;
            case "console_log":
                J$VM.System.log.println(data[1]);
                break;
            default:
                var fun = "on"+data[0];
                if(typeof this[fun] == "function"){
                    this[fun](data[1]);
                }
            }
        }else{
            if(typeof this.onmessage == "function"){
                this.onmessage(data);
            }
        }
    };

    var _onerror = function(e){
        var evt = e.getData(), data;
        if(evt.source == self) return;
        J$VM.System.err.println(evt.data);
    };
    
    /**
     * Submit new task to the thread
     * 
     * @param task It should be a <code>Runnable</code> or a 
     * <code>context</code> in <code>Runnable</code>
     * @param isRunnable indicates whether the first parameter "task"
     * is a <code>Runnable</code>
     */
    this.submitTask = function(task, isRunnable){
        if(task == undefined || task == null) return;
        isRunnable = isRunnable || false;
        
        var context, run;
        if(isRunnable){
            context = task.context;
            run = task.run;
        }else{
            context = task;
            run = runnable.run;
        }

        var buf = new js.lang.StringBuffer();
        buf.append("var thi$ = {");
        buf.append("context:").append(JSON.stringify(context));
        buf.append(",run:").append(run);
        buf.append("}");

        var msg = buf.toString();
        //J$VM.System.err.println("Thread post msg: "+msg);
        if(self.Worker){
            worker.postMessage(msg);
        }else{
			// IE must
            worker.postMessage(msg, "*");
        }

    };
    
    /**
     * Start the thread
     */
    this.start = function(){
        this.submitTask(runnable, true);
    };
    
    /**
     * Stop the thread
     */
    this.stop = function(){
        if(worker.terminate){
            worker.terminate();
        }else{
            // For the iframe worker, what should be we do ?
        }
    };

    var _init = function(Runnable){
        runnable = Runnable || {
            context:{}, 
            
            run:function(){
                J$VM.System.out.println("Web Worker is running");
            }};
        
        var E = js.util.Event;
        var path = J$VM.env["j$vm_home"]+"/classes/js/util/";

        if(self.Worker){
            worker = new Worker(path+"Worker.js");
        }else{
            // iframe ?
            var iframe = document.createElement("iframe");
            iframe.style.cssText = "visibility:hidden;border:0;width:0;height:0;";
            document.body.appendChild(iframe);
            var text = "<html><head>" +
                "<meta http-equiv='X-UA-Compatible' content='IE=edge'>" +
                "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>"+
                "</head></html>";
            var doc = iframe.contentDocument, head, script;
            doc.open();
            doc.write(text);
            doc.close();

            head = doc.getElementsByTagName("head")[0];
            text = js.lang.Class.getResource(J$VM.env["j$vm_home"]+"/jsre.js");
            script = doc.createElement("script");
            script.type = "text/javascript";
            script.id = "j$vm";
			// Becase we don't use src to load the iframe, but the J$VM will use
			// "src" attribute to indicates j$vm home. So we use a special attribute
            // name "crs" at here. @see also js.lang.System#_buildEnv 
            script.setAttribute("crs",J$VM.env["j$vm_home"]+"/jsre.js");
            script.setAttribute("classpath","");
            script.text = text;
            text = js.lang.Class.getResource(path + "Worker.js");
            script.text += text;
            head.appendChild(script);
            head.removeChild(script);

            worker = iframe.contentWindow;
        }

        E.attachEvent(worker, "message", 0, this, _onmessage);
        E.attachEvent(worker, "error", 0, this, _onerror);

    };

    _init.$bind(this)(Runnable);
    
}.$extend(js.lang.Object);
 
4、Worket.jsの実現
      
     Worket.jsはWeb WorketまたはIFrame WorkersがローディングしてOnmessageを処理する必要があります.私の実現では、js.lang.Threadのように、通常の意味のクラスではなく、簡単なjavascriptファイルです.js.utilのこのディレクトリで管理されています.
var isWebWorker = function(){
    try{return (window) ? false : true;} catch (x) {return true;}
}();

var _onmessage = function(e){
    if(isWebWorker){
        eval(e.data);
    }else{
        var _e = e.getData();
        if(_e.source == self) return;

        eval(_e.data);
    }

    thi$.run.call(thi$);
};

if(isWebWorker){
    importScripts("../../../jsre.js");
    onmessage = _onmessage;
}else{
    js.util.Event.attachEvent(window, "message", 0, this, _onmessage);
}
  5、結論
    
以上のコードは、すでにGoogleコードに公開されています.IE 8+、Firefox、Chromeブラウザをテストしました.正常に動作します.
      
     今後はJavascriptで、やっとJavaのようにマルチスレッド計算技術が使えるようになりました.もちろんWeb Worker自体の制限は避けられないです.