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 阅读(6771) 评论(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 多线程框架吧,是个日本人开发的,我刚刚知道这东西,还没仔细研究他的代码,的确是个好东西。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问