改进了一下,现在允许在一个运行周期里面运行多个command,同时提供了对线程延迟的支持(见executeCommands函数中)。任务是计算1+2+3...+1000累加的结果。现在让每个任务运行完成后延迟2秒再清楚自己的运行结果。点击一次鼠标就建立一个线程。<html>
<head>
<title>emu -- 用command模式模拟多线程</title>
</head>
<body>
<SCRIPT LANGUAGE="JavaScript">
<!--
if (Array.prototype.shift==null)
Array.prototype.shift = function (){
var rs = this[0];
for (var i=1;i<this.length;i++) this[i-1]=this[i]
this.length=this.length-1
return rs;
}
if (Array.prototype.push==null)
Array.prototype.push = function (){
for (var i=0;i<arguments.length;i++) this[this.length]=arguments[i];
return this.length;
}var commandList = [];
var nAction = 0;//控制每次运行多少个动作
var functionConstructor = function(){}.constructor;
function executeCommands(){
for (var i=0;i<nAction;i++)
if (commandList.length>0){
var command = commandList.shift();
if (command.constructor == functionConstructor)
if (command.scheduleTime == null || new Date()-command.scheduleTime>0)
command();
else
commandList.push(command);
}
}
function startNewTask(){
var resultTemp = document.getElementById("sampleResult").cloneNode(true);
with (resultTemp){
id="";style.display="block";style.color=Math.random()*(2<<23.5);
}
document.body.insertBefore(resultTemp,document.body.lastChild);
    commandList.push(function(){simThread(resultTemp,1);});
nAction++;
}function  simThread(temp,n){
if (temp.stop) n--;
else temp.innerText = temp.innerText-(-n);
if (n<1000)
commandList.push(function(){simThread(temp,++n)});
else{
var command = function(){document.body.removeChild(temp);;nAction--;};
command.scheduleTime = new Date()-(-2000);
commandList.push(command);
}
}window.onload = function(){setInterval("executeCommands()",1);}
//-->
</SCRIPT>
<button onclick="startNewTask()">开始新线程</button><BR><BR>
<div id=sampleResult onmouseover="this.stop=true" onmouseout="this.stop=false" style="display:none;cursor:hand">0</div>
</body>
</html>看了一下cpu占用,开1个任务和10个任务的cpu占用基本上没有区别。其实真正用在任务上的cpu时间是很少的。

解决方案 »

  1.   

    改进了一下,现在允许在一个运行周期里面运行多个command,同时提供了对线程延迟的支持(见executeCommands函数中)。任务是计算1+2+3...+1000累加的结果。现在让每个任务运行完成后延迟2秒再清楚自己的运行结果。点击一次鼠标就建立一个线程。<html>
    <head>
    <title>emu -- 用command模式模拟多线程</title>
    </head>
    <body>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    if (Array.prototype.shift==null)
    Array.prototype.shift = function (){
    var rs = this[0];
    for (var i=1;i<this.length;i++) this[i-1]=this[i]
    this.length=this.length-1
    return rs;
    }
    if (Array.prototype.push==null)
    Array.prototype.push = function (){
    for (var i=0;i<arguments.length;i++) this[this.length]=arguments[i];
    return this.length;
    }var commandList = [];
    var nAction = 0;//控制每次运行多少个动作
    var functionConstructor = function(){}.constructor;
    function executeCommands(){
    for (var i=0;i<nAction;i++)
    if (commandList.length>0){
    var command = commandList.shift();
    if (command.constructor == functionConstructor)
    if (command.scheduleTime == null || new Date()-command.scheduleTime>0)
    command();
    else
    commandList.push(command);
    }
    }
    function startNewTask(){
    var resultTemp = document.getElementById("sampleResult").cloneNode(true);
    with (resultTemp){
    id="";style.display="block";style.color=Math.random()*(2<<23.5);
    }
    document.body.insertBefore(resultTemp,document.body.lastChild);
        commandList.push(function(){simThread(resultTemp,1);});
    nAction++;
    }function  simThread(temp,n){
    if (temp.stop) n--;
    else temp.innerText = temp.innerText-(-n);
    if (n<1000)
    commandList.push(function(){simThread(temp,++n)});
    else{
    var command = function(){document.body.removeChild(temp);;nAction--;};
    command.scheduleTime = new Date()-(-2000);
    commandList.push(command);
    }
    }window.onload = function(){setInterval("executeCommands()",1);}
    //-->
    </SCRIPT>
    <button onclick="startNewTask()">开始新线程</button><BR><BR>
    <div id=sampleResult onmouseover="this.stop=true" onmouseout="this.stop=false" style="display:none;cursor:hand">0</div>
    </body>
    </html>看了一下cpu占用,开1个任务和10个任务的cpu占用基本上没有区别。其实真正用在任务上的cpu时间是很少的。
      

  2.   

    改了一下,现在可以在firefox下面运行了:<html>
    <head>
    <title>emu -- 用command模式模拟多线程</title>
    </head>
    <body>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    if (Array.prototype.shift==null)
    Array.prototype.shift = function (){
    var rs = this[0];
    for (var i=1;i<this.length;i++) this[i-1]=this[i]
    this.length=this.length-1
    return rs;
    }
    if (Array.prototype.push==null)
    Array.prototype.push = function (){
    for (var i=0;i<arguments.length;i++) this[this.length]=arguments[i];
    return this.length;
    }var commandList = [];
    var nAction = 0;//控制每次运行多少个动作
    var functionConstructor = function(){}.constructor;
    function executeCommands(){
    for (var i=0;i<nAction;i++)
    if (commandList.length>0){
    var command = commandList.shift();
    if (command.constructor == functionConstructor)
    if (command.scheduleTime == null || new Date()-command.scheduleTime>0)
    command();
    else
    commandList.push(command);
    }
    }
    function startNewTask(){
    var resultTemp = document.getElementById("sampleResult").cloneNode(true);
    with (resultTemp){
    id="";style.display="block";style.color=(Math.floor(Math.random()* (1<<23)).toString(16)+"00000").substring(0,6);
    }
    document.body.insertBefore(resultTemp,document.body.lastChild);
        commandList.push(function(){simThread(resultTemp,1);});
    nAction++;
    }function  simThread(temp,n){
    if (temp.stop) n--;
    else temp.innerHTML = temp.innerHTML - (-n);
    if (n<1000)
    commandList.push(function(){simThread(temp,++n)});
    else{
    var command = function(){document.body.removeChild(temp);;nAction--;};
    command.scheduleTime = new Date()-(-2000);
    commandList.push(command);
    }
    }window.onload = function(){setInterval("executeCommands()",1);}
    //-->
    </SCRIPT>
    <button onclick="startNewTask()">开始新线程</button><BR><BR>
    <div id=sampleResult onmouseover="this.stop=true" onmouseout="this.stop=false" style="display:none;cursor:hand">0</div>
    </body>
    </html>主要是改了: else temp.innerHTML = temp.innerHTML - (-n);
    和:style.color=(Math.floor(Math.random()* (1<<23)).toString(16)+"00000").substring(0,6);
      

  3.   

    emu 的东东必是精品, 支持地说
      

  4.   

    在firefox下面屏幕闪的很厉害,估计是firefox为了支持多平台没有调用directX写屏造成屏幕显示不流畅,有没有高手能解决这个问题呢?
      

  5.   

    其实command模式只是用来模拟多线程而已,并不是真的实现了多线程,象暂停,重新开始,同步,信号这些当然也只能模拟实现。象我上面的代码看起来都可以暂停(鼠标指向一个任务的时候它就暂停运算了),重新开始(鼠标移开),schedule(一个任务结束后我安排它延迟两秒后把结果擦除)。至于线程间的通讯和同步等高级功能,就算在java里面也不是那么简单的,君不见jdk每次升级往往都会在这方面做一些增强,网上杂志上讨论这个话题的文章也铺天盖地。用脚本来模拟这个东西一是做不好,二是实用性不强,做出来了多半也就是“玩的彻底”一点而已。
      

  6.   

    顺便用多线程帮我解决这个问题吧,异步带回的HTML代码写到DIV中去 但两个函数同时执行时第一个会写不了,因为第2个没等第一个返回HTML代码就已经执行了就中断了第一个,代码如写<script language="javascript">
    /****************************************************************
    * 函数名:fnDo
    * 功能描述:向指定的DIV/SPAN中写入异步带回的HTML代码
    * 输入:
    * 版本:2005-05-27 by lt
    /***************************************************************/
    function fnDo(ID,sDiv,sUrl)
    {
      sDiv.innerHTML = "Loading..."
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    var xmlDom = new ActiveXObject("Msxml2.DOMDocument");         
        var strURL = sUrl + ID;
            
        xmlhttp.Open("POST",strURL , true);
        xmlhttp.onreadystatechange = function(){
    var state = xmlhttp.readyState;

    var xmlDom = new ActiveXObject("Msxml2.DOMDocument");

    if (state == 4)
    {
    xmlDom.loadXML(xmlhttp.responseXML.xml);
       //alert(xmlDom.documentElement.selectSingleNode("//objXML").text)
    var getInfo = xmlDom.documentElement.selectSingleNode("//objXML").text;
    sDiv.innerHTML = getInfo
    }        
    };
        xmlhttp.Send(xmlDom);
    return 1;
    }
    //--------------------------------------------------------
    </script>
    <div id="divCategroy"></div>
    <div id="divContent"></div>
    <script language="javascript">
    fnDo(0,divCategroy,"getcategory.asp?ID=")
    fnDo(0,divContent,"getcategory.asp?ID=")
    </script>
      

  7.   

    回复人: emu_ston(吃的就是没文化的亏) ( ) 信誉:127  2005-06-10 10:10:00  得分: 0  
    "其实command模式只是用来模拟多线程而已,并不是真的实现了多线程"----
    不少朋友喏喏称是,所以正在怀疑自己呢,
    function  simThread(temp,n){
    在这一句后加了一句:
        if(Math.random()>0.99) alert();
    测试结果分明就是单线程啊 捊须深思中。
      

  8.   

    虽说script本身不支持多线程
    但是多个窗口里的script可以同时运行,也可以当多线程看,
    还有window.showModelessDialog()它事实是也是多提供一个线程。回复人: a040liutao(冬之心) ( ) 信誉:100  2005-06-10 10:25:00  得分: 0  
    的问题,可以参考:
    http://jkisjk.vip.sina.com/html/getDataFromServer.htm 的第一种方式
      

  9.   

    好像可以利用iframe来模拟多线程的,学习楼主的办法
      

  10.   

    JK_10000(JK)  你给的地址打不开
      

  11.   

    试验了一下,iframe只能用来建立新的变量命名空间,却没有办法创建互不干扰的进程,一个iframe里面在执行运算任务的时候,其他的框架和主框架全部都被堵塞住了,没有办法实现上面的功能:<html>
    <head>
    <title></title>
    </head>
    <body>
    <button onclick="newTask()">new task</button>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    var framesCount = 0;
    function newTask(){
    var elm = document.createElement("iframe");
    document.body.insertBefore(elm);
    elm.style.display="none";
    framesCount++;
    document.frames[framesCount-1].document.write("<script>for (var i=0,n=0;i<=1000000;n+=i++);alert(n)<\/script>")
    }
    //-->
    </SCRIPT>
    </body>
    </html>点击按钮的时候开始执行运算,在运算结束前没有办法再点击一次按钮来开启一个新线程的。
    modaldialog是肯定会堵塞主窗口的。开新窗口还有点用:
    <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>
      

  12.   

    演示iframe确实会相互堵塞的一个更好的例子:<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>
      

  13.   

    前些天不是有一个帖子介绍了基于 HTTP 的 QQ 协议吗,我按照这个写了一个 QQ 客户端,在 WSH 里啊,HTML 里啊都可以运行的。就因为只有一个线程头疼来着,Tencent 服务器现在太慢了,发一条消息会急死人的。Emm... 先 Mark ,再仔细看看~~
      

  14.   

    iframe确实会相互堵塞:test.html-----------
    <iframe src="a1.html" > </iframe>
    <iframe src="a1.html" > </iframe>a1.html------------
    <script language=javascript >
    alert();
    </script>两个alert不能同时出现,证明不是真正的多线程
      

  15.   

    用showModelessDialog来模拟多线程的不足是:没法把这个对话框移出视线外。
    开多个窗口,让多个窗口里的script各自执行,来模拟多线程应该可行。下例是非模态alert,也应该算是模拟多线程的一种应用:
    http://jkisjk.vip.sina.com/html/closeAlertBox.htm
      

  16.   

    回复人: a040liutao(冬之心) ( ) 信誉:100  2005-06-10 14:52:00  得分: 0  -----
    可能是有时网络不好
      

  17.   

    jk:
    showModelessDialog是我所知道的唯一能够堵塞正在运行的进程的方法,怎么可能用它来模拟多线程呢?你没有办法同时显示多个模式对话框,因为显示第一个的时候主页面的线程就停下来等了,一直到关掉它第二个才有可能打得开。
      

  18.   

    哦看错了,我说的是modalDialog,你说的是showModelessDialog呵呵,全乱套了。
      

  19.   

    http://jkisjk.vip.sina.com/html/closeAlertBox.htm上面的非模态alert与自动关闭alert,
    也应该算是模拟多线程的一种应用,可以同时弹出多个alert框
    用的是showModelessDialog方式
    因为当时看到有朋友发贴要求“自动关闭alert对话框”,
    所以写了个来凑热闹,尽管没有实际用途。----捊须而笑
      

  20.   

    年纪到,容易生感慨
    附庸下风雅,辱没次期文,
    聊以自娱,料无大妨刮胡子刀就免了,
    这些事让我儿我女婿送就得,
    不敢劳stone大驾。捊须而笑--
      

  21.   

    onreadystatechange函数来处理回调的时候更象多线程的效果些
      

  22.   

    不明白你的意思。你是说window.open之后在新窗口的onreadystatechange里面回掉主页面吗?
      

  23.   

    我想fason就是这个意思.不过解释执行的脚本程序不管如何模拟,离多线程还远着呢.
    onreadystatechange我也试过,其中一个onreadystatechange执行阻塞,其余onreadystatechange永远都没机会执行.
    可以这么测试一下:
    用两个iframe加载两个htm,其中一个iframe的onreadystatechange中使用模式对话框
    你会发现,先加载完成的页面显示模式对话框,在未被确认之前,第二个页面永远没有机会加载完成.
      

  24.   

    sorry,看来我说错了,ie6看起来不一样
      

  25.   

    不过如下的测试页面可以说明问题:
    x.htm    /*****直接在地址栏输入x.htm并回车,这时候你可能看不到两个alert同时出现的情况,并且在这种情况下,必须将该alert消息确认之后,两个文档才加载完成
    <script>
    function test()
    {
    var sDialogHW = "dialogWidth:350px; dialogHeight:250px;status:no;";
    var sDialogULR = "about:blank";
    retDlg=window.showModalDialog(sDialogULR,null,sDialogHW);
    }
    </script>
    <iframe onreadystatechange="test()" src="y.htm"></iframe>
    <iframe onreadystatechange="test()" src="z.htm"></iframe>
    y.htm
    <script>
    alert(1)
    </script>
    <b>finish</b>
    z.htm
    <script>
    alert(2)
    </script>
    <b>finish2</b>