在Javascript中用command模式模拟多线程,包含注释
Javascript本身是不支持多线程的,直到在网上看到这样一篇文章, javascript中用command模式模拟多线程中 ,觉得非常好,用command模式,巧妙的模拟了多线程.虽是模拟,但很实用.对于javascript不熟的人,可能很难去理解,因此添加了注释,重新发布出来。希望能给需要的人一点帮助。
上面值得说明的是几个对象:
一,CommandList为一个ArrayList对象,可以通过ArrayList.shift()取出第一个元素,可通过ArrayList.push()将元素放进去.其ArrayList中保存的对象为Command.
二,Command对象为一个函数如下,可以直接执行.
function (){simThread(resultTemp,n);}其中n是可以传递的变量
三,command.constructor即FunctionConstructor
function Function()
{
[native code]
}
<html>
<head>
<title>用command模式模拟多线程</title>
</head>
<body>
<script language="JavaScript" type="text/javascript">
<!--
//objectName.prototype:返回Array对象类型原型的引用
//命令出队列,返回第一个元素
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 ()
{
//arguments原本为Array中的队列的标志
for (var i=0;i<arguments.length;i++) this[this.length]=arguments[i];
return this.length;
}
//为一个ArrayList对象,其属性shift将返回队列中的第一个元素,即一个函数对象.
var commandList = [];
//控制每次运行多少个动作
var nAction = 0;
//object.constructor表示创建对象的函数
var functionConstructor = function(){}.constructor;
//用于增加线程。克隆一个div对象,添加到页面,并且进站simThread命令
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); //否则数据+n
}
if (n<1000)
{
//每次执行的时候都会将CommandList中第一个元素拿出来执行.因此队列中将减少一个.
//在n<1000,即还没有加到500500的时候,需要将正在执行的线程,以及n的值加1后添加到队列的末尾
//执行到下一个循环的时候再执行
commandList.push(function(){simThread(temp,++n)});
}
else
{
//当已经执行到500500的值,即n=1000后,需要将线程注销
var command = function()
{
//从页面移除线程
document.body.removeChild(temp);
nAction--;
};
command.scheduleTime = new Date()-(-2000);
//从Arraylist中注销模拟显示的线程
commandList.push(command);
}
}
window.onload = function()
{
setInterval("executeCommands()",1);//每隔1秒,执行函数executeCommands()
}
//让多个函数可以一起执行的方法。
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(); //执行函数simThread
else
commandList.push(command); //增加一个线程
}
}
//-->
</script>
<button onclick="startNewTask()">开始新线程</button>
<br/>
<div id="sampleResult" onmouseover="this.stop=true" onmouseout="this.stop=false" style="display:none;cursor:hand">0</div>
</body>
</html>
<head>
<title>用command模式模拟多线程</title>
</head>
<body>
<script language="JavaScript" type="text/javascript">
<!--
//objectName.prototype:返回Array对象类型原型的引用
//命令出队列,返回第一个元素
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 ()
{
//arguments原本为Array中的队列的标志
for (var i=0;i<arguments.length;i++) this[this.length]=arguments[i];
return this.length;
}
//为一个ArrayList对象,其属性shift将返回队列中的第一个元素,即一个函数对象.
var commandList = [];
//控制每次运行多少个动作
var nAction = 0;
//object.constructor表示创建对象的函数
var functionConstructor = function(){}.constructor;
//用于增加线程。克隆一个div对象,添加到页面,并且进站simThread命令
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); //否则数据+n
}
if (n<1000)
{
//每次执行的时候都会将CommandList中第一个元素拿出来执行.因此队列中将减少一个.
//在n<1000,即还没有加到500500的时候,需要将正在执行的线程,以及n的值加1后添加到队列的末尾
//执行到下一个循环的时候再执行
commandList.push(function(){simThread(temp,++n)});
}
else
{
//当已经执行到500500的值,即n=1000后,需要将线程注销
var command = function()
{
//从页面移除线程
document.body.removeChild(temp);
nAction--;
};
command.scheduleTime = new Date()-(-2000);
//从Arraylist中注销模拟显示的线程
commandList.push(command);
}
}
window.onload = function()
{
setInterval("executeCommands()",1);//每隔1秒,执行函数executeCommands()
}
//让多个函数可以一起执行的方法。
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(); //执行函数simThread
else
commandList.push(command); //增加一个线程
}
}
//-->
</script>
<button onclick="startNewTask()">开始新线程</button>
<br/>
<div id="sampleResult" onmouseover="this.stop=true" onmouseout="this.stop=false" style="display:none;cursor:hand">0</div>
</body>
</html>
上面值得说明的是几个对象:
一,CommandList为一个ArrayList对象,可以通过ArrayList.shift()取出第一个元素,可通过ArrayList.push()将元素放进去.其ArrayList中保存的对象为Command.
二,Command对象为一个函数如下,可以直接执行.
function (){simThread(resultTemp,n);}其中n是可以传递的变量
三,command.constructor即FunctionConstructor
function Function()
{
[native code]
}