emu in blogjava

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            171 隨筆 :: 103 文章 :: 1052 評論 :: 2 Trackbacks

                  作者:emu(黃希彤)今天和徐鵬程msn的時候聊起javascript不支持多線程。以前也看過有高手在wsh上可以創建thread對象,但是畢竟不是常規手段,我們做web應用一般沒有本地訪問權限的,用activex的沒試過,畢竟也不是javascript方式。

                  以前我們解決這樣的問題都是針對具體問題寫一段代碼來模擬多線程的,但是由于往往要對沒個線程單獨編碼,這樣的代碼十分冗長。學習設計模式的時候就曾經考慮過在javascript中實用command模式來更好的模擬多線程,但是一直沒有付諸實施,今天既然想起來了就試試看:

           1<html><head><title>emu -- 用command模式模擬多線程</title></head><body>
           2<SCRIPT LANGUAGE="JavaScript">
           3<!--
           4if (Array.prototype.shift==null)
           5Array.prototype.shift = function (){
           6    var rs = this[0];
           7    for (var i=1;i<this.length;i++this[i-1]=this[i]
           8    this.length=this.length-1
           9    return rs;
          10}

          11if (Array.prototype.push==null)
          12Array.prototype.push = function (){
          13    for (var i=0;i<arguments.length;i++this[this.length]=arguments[i];
          14    return this.length;
          15}

          16
          17var commandList = [];
          18var nAction = 0;//控制每次運行多少個動作
          19var functionConstructor = function(){}.constructor;
          20function executeCommands(){
          21    for (var i=0;i<nAction;i++)
          22        if (commandList.length>0){
          23            var command = commandList.shift();
          24            if (command.constructor == functionConstructor)
          25                if (command.scheduleTime == null || new Date()-command.scheduleTime>0)
          26                    command();
          27                else
          28                    commandList.push(command);
          29        }

          30}

          31
          32function startNewTask(){
          33    var resultTemp = document.getElementById("sampleResult").cloneNode(true);
          34    with (resultTemp){
          35    id="";style.display="block";style.color=(Math.floor(Math.random()* (1<<23)).toString(16)+"00000").substring(0,6);
          36    }

          37    document.body.insertBefore(resultTemp,document.body.lastChild);
          38    commandList.push(function(){simThread(resultTemp,1);});
          39    nAction++;
          40}

          41
          42function  simThread(temp,n){
          43    if (temp.stop) n--;
          44    else temp.innerHTML = temp.innerHTML - (-n);
          45    if (n<1000)
          46        commandList.push(function(){simThread(temp,++n)});
          47    else{
          48        var command = function(){document.body.removeChild(temp);;nAction--;};
          49        command.scheduleTime = new Date()-(-2000);
          50        commandList.push(command);
          51    }

          52}

          53
          54window.onload = function(){setInterval("executeCommands()",1);}
          55//-->
          56
          </SCRIPT>
          57<button onclick="startNewTask()">開始新線程</button>
          58
          59<BR><BR>
          60<div id=sampleResult onmouseover="this.stop=true" onmouseout="this.stop=false" style="display:none;cursor:hand">0</div>
          61</body>
          62</html>

                  注意第26行。javascript里面函數也是對象,所以就沒有必要把函數調用包裝到do或者execute方法里面了,直接用()就可以讓函數對象運行起來:
          command();

                  shift和push函數是javascript中array對象的函數,可是IE5居然沒有定義,最前面兩個函數是為IE5準備的。

                  在IE和FireFox下面通過作者:emu(黃希彤)

          posted on 2005-06-08 20:29 emu 閱讀(6780) 評論(34)  編輯  收藏

          評論

          # re: 在javascript中用command模式模擬多線程 2005-06-14 19:25 emu
          有網友提出,每個內嵌框架(iframe)都有自己的window對象,應該可以分別在其中開啟獨立的線程。試驗后發現,所有的iframe其實都是在top的線程之中,他們的計算任務會相互堵塞,所以不可行:
          <html>
          <head>
          <title></title>
          </head>
          <body>
          <SCRIPT LANGUAGE="JavaScript">
          <!--
          var count1=0;
          var count2=0;
          var elm = document.createElement("iframe");
          document.body.insertBefore(elm);
          elm.style.display="none";
          document.frames[0].document.write("<script>setTimeout(\"for (var i=0,n=0;i<=10001;n+=i++){parent.count1=n;parent.status=parent.count1+' - '+parent.count2};\",1000)<\/script>")

          var elm = document.createElement("iframe");
          document.body.insertBefore(elm);
          elm.style.display="none";
          document.frames[1].document.write("<script>setTimeout(\"for (var i=0,n=0;i<=10001;n+=i++){parent.count2=n;parent.status=parent.count1+' - '+parent.count2};\",1000)<\/script>")
          //-->
          </SCRIPT>
          </body>
          </html>

          還有網友提出,新開窗口是運行的獨立的線程(或進程,取決于windows的配置)中,試驗了一下,確實是如此,如果需要在后臺做大量的運算的話可以考慮這種方式,運算速度比command模式模擬的要快幾個數量級:

          <html>
          <head>
          <title></title>
          </head>
          <body>
          <SCRIPT LANGUAGE="JavaScript">
          <!--
          function newTask(left){
          var win = window.open("","","top=300,height=100,status=yes,width=300,left="+left);
          win.document.write("<script>setTimeout('for (var i=0,n=0;i<=10001;n+=i++)status=n;',1000)<\/script>")
          }
          newTask(0);
          newTask(330);
          newTask(660);
          //-->
          </SCRIPT>
          </body>
          </html>
            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-02-12 14:44 rom
          有沒試過在js里實現 sleep 功能?  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-02-13 10:16 emu
          有阿,在上面的例子中點擊按鈕發起線程后,吧鼠標放到正在運行中的線程上,線程就會暫停下來知道鼠標離開。此外線程計算結束后也會延遲2秒清除結果,這個延遲也是使用sleep的方式實現的。看看 simThread 和 executeCommands 的相互配合。  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-02-15 15:53 rom
          不好意思,表達不清楚。我的意思是把 sleep 或 pause 寫成一個方法,可以在其他方法中直接調用。
          比如:

          function test(){
          alert((new Date().getTime());
          pause(1000);
          alert(new Date().getTime());
          }
            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-02-16 09:41 emu
          @rom
          只有使用異步設計的程序才能夠方便的控制“線程”的運行狀態,按照你貼出的代碼的暗示,pause方法是要堵塞主當前正在運行的腳本引擎進程,讓腳本引擎停止工作。但是堵塞進程會嚴重影響用戶體驗并占用大量cpu資源,建議采用異步方式改善設計來實現延遲。同步的堵塞方式實現如下:

          function test(){
            alert(new Date().getSeconds());
            pause(1000);
            alert(new Date().getSeconds());
          }
          function pause(n){
            for(var t = new Date();(new Date()-t<n););
          }
          test();

            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-02-16 12:02 rom
          用循環的那種當然不行。看過一個實現如下:

          <html>
          <head>
          <script language="javascript">
          function Pause(obj,iMinSecond){
          if (window.eventList==null) window.eventList=new Array();
          var ind=-1;
          for (var i=0;i<window.eventList.length;i++){
          if (window.eventList[i]==null) {
          window.eventList[i]=obj;
          ind=i;
          break;
          }
          }

          if (ind==-1){
          ind=window.eventList.length;
          window.eventList[ind]=obj;
          }
          setTimeout("GoOn(" + ind + ")",1000);
          }

          function GoOn(ind){
          var obj=window.eventList[ind];
          window.eventList[ind]=null;
          if (obj.NextStep) obj.NextStep();
          else obj();
          }


          function test(){
          alert("test1");
          Pause(this,1000);
          this.NextStep=function(){
          alert("test11");
          }
          }

          </script>
          </head>
          <body>
          <button onclick="test()">test</button>
          </body>
          </html>


          如果測試代碼如下就有問題了

          function test1(){
          alert("test1");
          Pause(this,1000);
          this.NextStep=function(){
          alert("test11");
          }
          }
          function test2(){
          alert("test2");
          Pause(this,1000);
          this.NextStep=function(){
          alert("test22");
          }
          }
          <button onclick="test1();test2()">test</button>  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-02-16 12:04 rom
          setTimeout("GoOn(" + ind + ")", 1000) 應是 setTimeout("GoOn(" + ind + ")", iMinSecond)  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-02-16 13:06 emu
          呵呵,看起來和我很久以前寫的例子非常像哦。
          我上面的解釋和上面你貼的代碼你都沒有理解到,跟你再解釋也說不明白了……  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-02-16 15:44 rom
          有勞再解釋一下^_^

          你覺得頂樓代碼的重用性如何?
          你對 jsvm 框架有什么看法?

            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-02-17 11:12 emu
          我對 jsvm 的看法在 http://community.csdn.net/Expert/topic/4559/4559660.xml 中講過了。我非常欣賞jsvm的設計,可是沒有嘗試過去用。

          頂樓的代碼沒什么可重用性,我寫blog和萬常華大哥寫jsvm的出發點是不同的,萬大哥希望可以既授人以魚又授人以漁,我則更愿意授人以漁,只希望可以把代碼后面的思想表達出來,把最困難最有價值的嘗試過程呈現出來,真正能看懂其中思想的人并不需要記住實現,下回遇到問題順手就可以寫出來了。就好像 http://community.csdn.net/Expert/topic/4555/4555563.xml 中,我對google的模仿并不在于看或抄google的代碼(到現在為止還沒有去看過google自定義模塊的原碼,可能以后有時間再去學習吧),而是理解了怎樣的用戶感受更爽,然后具體的實現其實不是關鍵問題(我相信我的實現和google的沒有多少相像的地方)。

          多線程方面我懂的也不多,解釋也解釋不好,講多錯多,還是自己去找資料好好學習吧。  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-03-16 23:50 guest
          如果每個command執行時間比較長,比如1秒,所有"線程"都會被影響  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-03-17 14:26 emu
          呵呵command模式本身沒有這個問題,對command的使用不當才會帶來問題。  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-11-22 18:08 009
          想問一下樓主“點擊這里查看效果”那個按鈕怎么添加的
          還有我加入html代碼的時候,顯示出來的“<>“靠中間都有一個空格,不知道為什么
            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-11-23 09:31 emu
          呵呵那個按鈕是手寫的。分析一下頁面源碼就明白了,要是分析不明白,那講也講不明白了。
            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-11-26 17:04 lingwj
          @emu
          這個方式實際用途不大,后臺的運算用戶不希望看到多出的窗口,而且,現在的瀏覽器大多會自動屏蔽javascript的運行,如果還要用戶點擊許可運行javascript運行的話,其效果可想而知  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-11-28 13:33 emu
          ;) 偶只是展示這樣一個計算,并不是在展示這樣一個顯示方式啊。
          現在的主流瀏覽器應該沒有默認自動屏蔽javascript的運行了吧?  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-12-28 10:04 putongren
          呵呵,學習!

          建議一下,可以在你的這段代碼中增加一些斷點支持功能,以便實現“線程”掛起、喚醒。線程的調度依然可以使用 setInterval。  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2006-12-28 17:09 emu
          我的例子中有啊,試試反復點擊按鈕啟動多個測試“線程”,然后把鼠標移動到正在運算中的“線程”上,它就會停下來。鼠標移開的時候它又繼續。  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2007-08-08 19:43 cnxmouse
          emu :
          花了幾個小時,認真看了一下你的程序,
          你的程序實現,我覺得不具有可用性,
          你的計算部分,已經作了分割處理,每個計算周期非常短,所以實現了"多線程"的效果,但是在實際的應用中,一個有實際用途的函數根本不可能這樣處理,如果人為的分割是非常難的,而且帶來了很多的不確定性,特別對于變量的使用上根本無法控制,
          05年的時候為了解決頁面效果,曾經也嘗試讓JS多線程,使用的是setTimeout,實現了一點的效果,但是我的本意"多線程"沒有實現.今年再回首,老問題依舊...
            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2007-08-17 16:57 小西
          to emu:
          跑了一下,好欣喜,再仔細看了一下程序,卻有些失望~

          如果光看運行效果,再結合這里“用Command模式模擬多線程”的標題,我還以為那n個閃動的運算是發生在n個固定的div標簽和n個固定的命令對象上,每個命令對象各自完成自己的 "1到1000連加" 的任務,并把任務的執行過程顯示到div中

          結果,一看代碼,只猜對三分之一!!!

          根本不是固定的命令對象,輪占時間片去完成各自的“命令”,而是把一個單純的命令分解成1000個“小命令”(每個小命令為了模擬大命令又會自己產生后繼小命令),然后把它們逐一丟進一個公共的“閥門”,這個閥門還做得挺巧妙,一進一出的,活生生的把人家的Array整成了“隊列”,最后每隔一毫秒反復地去“檢查”這個“閥門”里面的東西,滿足條件的,就把那個分解了的“小命令”執行掉,不滿足,就又塞回閥門里。。。


          說設計模式吧,人家那是為了簡化,清晰化業務模型的代碼實現啊,可是你這的代碼,活生生地把業務拆解了,把業務給復雜化了,然后才成全了你的“多線程”。。

          自以為很聰明的實現,實際上真的很難推廣開來
          你看看你的function(){simThread(...)}對象,在循環和嵌套中反反復復構造了多少次? 再看看你那些內嵌函數因為綁定了外部函數的本地變量而產生的閉包,內存有泄漏嗎?變量好控制嗎?

          你的實現,根本不是用命令對象模擬多線程,本質上就是用for循環模擬多線程!!!你的本質就是把最清晰的業務命令,從代碼的角度分解成了更小的,更不好控制的,只有你自己懂的“命令對象”,你這種做法純粹是偷換概念,吸引眼球!!!!難怪樓上有些人說不實用呢 ,真的不實用,絲毫沒有從本質上解決問題。





            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2007-08-17 18:12 emu
          偶從來沒有說過模擬多線程問題或者大計算量造成瀏覽器失去響應問題用command模式就可以很漂亮地輕松解決了,只是演示了如何這樣做的一個方法而已。樓上各位看來對偶的期望太高了。

          javascript作為一個單進程的解釋語言,“活生生地把業務拆解了”恐怕是避免長時間持續運算導致瀏覽器失去響應的惟一出路了。command模式提供給了我們一個可能的分解計算的方式。同時把計算分解后也讓多個模擬線程并行計算和按需要調度提供了可能。

          樓上的最后一段偶是不同意的,用“for循環模擬多線程”是說不通的。executeCommands中的for循環是一個合理的進程調度的可能實現方式。

          偶還想更正一下樓上對于設計模式的誤解。“說設計模式吧,人家那是為了簡化,清晰化業務模型的代碼實現啊”這是樓上自己對設計模式的理解而已。設計模式是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結,它并不背負有“簡化,清晰化業務模型”的使命,雖然有的時候它看起來確實有這樣的效果。舉個最常見的例子,用對象池方式來處理數據庫連接(連接池),肯定要比每次訪問數據庫都創建連接,用完關閉連接,來得不“簡化”,不“清晰”,而且帶來了很多原來不曾存在的極其麻煩的問題,但是它能有效提高效率,節省資源,因此除了初學者,我們幾乎從來不會嘗試每次訪問數據庫都去創建連接。

          用復雜化了業務邏輯來指責偶使用command模式的方式,就好像去指責連接池是復雜化了數據庫訪問的業務邏輯一樣,是置我們解決了的問題于不顧,而只著眼于我們付出的代價。其實我們提供一個問題的解決方案的時候,一般并不意味著發明了銀彈。

          說偶偷換概念,吸引眼球,偶就實在是很無語了,分享一點技術心得用得著扣這么大的帽子給偶嘛?在樓上諸位提出更漂亮的實現之前,這是偶目前的技術能力做能做到的最漂亮的實現了,難道是特地發出來害人的?難道寫blog有人給稿費的?  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2007-10-26 15:27 Little燕
          偶這段時間也在整js多線程的問題,不經意看到了樓主的這篇文章,覺得還不錯,雖然實用性不是很好(呵呵,我的個人意見!),但還是可以學習一下啦!  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2007-12-14 18:57 neetoo
          似乎也只有這種準異步方式了  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2007-12-18 16:35 emu
          除非打開獨立的新窗口來進行計算。
          內嵌的框架似乎是在同一個線程上跑的,獨立的新窗口根據系統設置可以在獨立的線程或者進程上跑(優化大師有這個設置項),如果有多核的話似乎還可以在不同的核上跑。  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2008-03-03 22:40 游客
          能不能同時彈出一大堆窗口呢?用alert().  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2008-03-04 12:32 游客
          有一個函數要執行3組for循環,每組250多次,循環后有延遲的現象,所以想用多線程將循環分成多個函數同時執行,如果能同時彈出多個alert窗口,那證明多線程是成功的,試了下用settimeout與setinterval都不行,不知前輩有無可行的方法?  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2008-03-08 21:04 emu
          呵呵我前面說過了,真正的多線程目前還不能實現(期待未來的瀏覽器吧)。至于同時彈出多個alert窗口并不難,也證明不了多線程。下面的代碼在我的機器上可以同時彈出來若干個alert。試試不要點確定,直接把前面的拖開:)
          var a=0;
          for(var i=0;i<10;i++){
          var x=new ActiveXObject("Microsoft.XMLHTTP");
          x.onreadystatechange=function(xx){return function(){if(xx.readyState==4)alert(a++)}}(x)
          x.open("get","http://127.0.0.1:44444",true);
          x.send("")
          }
          本地44444端口上沒有開任何服務的情況下測試的。
            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2008-03-11 19:36 游客
          看來這js還真不能實現多線程呢.
          你最開始寫的代碼的文本域內有行號顯示,怎么實現的?
          有一個問題困擾了我很久了,如果要在js代碼里建立事件監聽該如何實現?我知道的只有兩個方法:在對象里加<div id="id" onkeydown=""></div>;還有一個<script type="text/javascript" for="id" event="onclick">alert();</script>
          如果不用這兩個還有其它方法嗎?比如在<script type="text/javascript">事件</script>里面加事件監聽.我能想到的都試過了,沒有效果.前輩在js方面有很高深的造詣,相信你會有辦法的.  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2008-03-12 01:29 emu
          不知道你指的是不是addEventListener/attachEvent這樣的?
          onXXX句柄很多也可以直接賦值的,事件名全小寫就好了。  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2008-03-12 20:11 游客
          找了一些attachEvent與addEventListener的介紹文章,用以下的實例試了下,沒有效果,
          var obj=document.getElementById("body");
          obj.attachEvent("onload",alert(5));
          能不能給個具體的實例方案?

          問一下網頁加密的問題,如果是普通的加密,網絡上有很多在線加解密的工具,請問能否在為網頁加密時加密碼而瀏覽器又能打開?

          在網上找到的一個用MD5加密的工具,但是在源碼里可以看到密碼,源碼太長了,粘不上來.

          http://www.cha88.cn
            回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2008-03-13 14:24 emu
          呵呵網上能查得到答案的問題不要那么懶了。  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2008-05-16 17:37 A Java DEV
          寫得很好,
          這里提出了個線程設計模式,
          巧妙堆棧的設計,獨立的處理對象 function.
          當然一些公用變量的用地要小心
          線程的執行,時序是很關鍵的
          數據共享 和 數據分離,是要解決的關鍵問題
          其實大多數這些數據是要靠developer來提取和分離的
          這里的代碼反應了一個正確的線程執行模式!我支持!  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程[未登錄] 2008-05-20 16:52 TY
          對內容了解遲了一些,但覺得內容比較新。
          學習中。  回復  更多評論
            

          # re: 在javascript中用command模式模擬多線程 2008-08-13 11:01 wudale
          樓主的代碼,只能說從視覺效果上實現了多線程而已,適用范圍非常有限。大家去看看 Concurrent.Thread.js 這個javascript 多線程框架吧,是個日本人開發的,我剛剛知道這東西,還沒仔細研究他的代碼,的確是個好東西。  回復  更多評論
            


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 仪征市| 聂荣县| 平凉市| 浠水县| 永顺县| 孝义市| 荣昌县| 运城市| 巧家县| 修水县| 江孜县| 武宁县| 林芝县| 克拉玛依市| 泌阳县| 弥渡县| 郯城县| 中山市| 水富县| 青川县| 英德市| 连江县| 呼玛县| 土默特右旗| 克山县| 桑日县| 广元市| 襄樊市| 宁城县| 大渡口区| 九江县| 秦安县| 梅州市| 普洱| 汝州市| 达孜县| 五台县| 涟水县| 佛冈县| 新津县| 和田市|