js闭包:使用JS闭包特性模拟的多线程来源: 发布时间:星期五, 2009年9月25日 浏览:59次 评论:0
最近在做一个项目,由于对JS的一些特性不是很熟悉,走了些弯路,不过到最后总算解决了问题。现在把项目中一些经验心得发出来,希望能对以后解决问题的人有些帮助。 简单描述下项目需求:网络中有一台主机(Web站点),需要对分布到各地的节点发送命令,检测命令执行结果,同时进行状态检测。由于各地节点是同构的,所以希望在进行命令执行和状态检测时,能够起多个线程,每个线程对应一个节点,将结果即时反应到页面。 最开始的设想是这样的:把所有的节点放到数组,页面开始执行时遍历数组,将节点作为参数传递到实际中的函数,函数使用setInterval来启动,以此来模拟多线程。 代码如下:见index1.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML> <HEAD> <TITLE> 实例1 </TITLE> <META NAME="Generator" CONTENT="EditPlus"> <META NAME="Author" CONTENT=""> <META NAME="Keywords" CONTENT=""> <META NAME="Description" CONTENT=""> </HEAD> <BODY> <SCRIPT LANGUAGE="JavaScript"> <!-- function Node(id,name,cn){ this.id = id; this.name = name; this.cn = cn; } var nodes = new Array(); nodes[0] = new Node(1,"node1","节点1"); nodes[1] = new Node(2,"node2","节点2"); var nodeConfig = {}; nodeConfig.ticks = 4 * 1000; //刷新频率 nodeConfig.msg = "运行中 ";function showStatus(node){ alert(node.name + ":" + nodeConfig.msg); } function start(){ var len = nodes.length; for (var i =0; i < len ; i++){ setInterval(function(){showStatus(nodes[i])} ,nodeConfig.ticks); } } start(); //--> </SCRIPT> </BODY> </HTML> 正当我信心满满的想查看结果时,发现出错。查找了一些资料,大概明白是由于setInterval执行时,传进来的形参已经脱离了其定义的函数环境,已经被垃圾回收器回收了。 由于时间紧迫,来不及细查资料,暂时采取了一种其他的方法来实现:每个节点对应一个函数。 代码如下:见index2.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML> <HEAD> <TITLE> 实例2 </TITLE> <META NAME="Generator" CONTENT="EditPlus"> <META NAME="Author" CONTENT=""> <META NAME="Keywords" CONTENT=""> <META NAME="Description" CONTENT=""> </HEAD> <BODY> <SCRIPT LANGUAGE="JavaScript"> <!-- function Node(id,name,cn){ this.id = id; this.name = name; this.cn = cn; } var nodes = new Array(); nodes[0] = new Node(1,"node1","节点1"); nodes[1] = new Node(2,"node2","节点2"); var nodeConfig = {}; nodeConfig.ticks = 4 * 1000; //刷新频率 nodeConfig.msg = "运行中 ";function showStatus1(node){ alert(node.name + ":" + nodeConfig.msg); } function showStatus2(node){ alert(node.name + ":" + nodeConfig.msg); } function start(){ setInterval(function(){showStatus1(nodes[0])} ,nodeConfig.ticks); setInterval(function(){showStatus2(nodes[1])} ,nodeConfig.ticks); } start(); //--> </SCRIPT> </BODY> </HTML> 此段代码能够执行,但是其缺陷显而易见:每当增加一个节点时,就要手动的去改代码,增加函数。而这些代码大部分都是相同的,虽然可以直接Copy,维护难度却会一直增加,一不小心就不知道是哪个节点更改错了。 稍微闲下来时,继续查找资料,终于找了闭包的概念。关于闭包的介绍,此处只是简单概述,具体的可以看下面的参考资料,那里面介绍的很详细。 所谓“闭包”,就是在构造函数体内定义另外的函数作为目标对象的方法函数,而这个对象的方法函数反过来引用外层函数体中的临时变量。这使得只要目标对象在生存期内始终能保持其方法,就能间接保持原构造函数体当时用到的临时变量值。(引自参考文章) 我自己的理解就是:外部变量保存了某个内部函数的指针,由于JS垃圾回收机制,也间接的保存了内部函数定义环境的一些变量。 呵呵,知道这个方法后,就对原来的代码改写一遍。 代码如下:见index3.html
此次程序终于按最初的想法运行了。并且以后随着节点的增加,不会像代码2那样Copy一堆函数了,只需要在数组里面增加一个节点就可以。 为了更OO一点,又对程序重构了一番。 代码如下:见index4.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML> <HEAD> <TITLE> 实例4 </TITLE> <META NAME="Generator" CONTENT="EditPlus"> <META NAME="Author" CONTENT=""> <META NAME="Keywords" CONTENT=""> <META NAME="Description" CONTENT=""> </HEAD> <BODY> <SCRIPT LANGUAGE="JavaScript"> <!-- var nodeConfig = {}; nodeConfig.ticks = 4 * 1000; //刷新频率 nodeConfig.msg = "运行中 ";function Node(id,name,cn){ this.id = id; this.name = name; this.cn = cn; } //节点数组可从服务器端生成 var nodes = new Array(); nodes[0] = new Node(1,"node1","节点1"); nodes[1] = new Node(2,"node2","节点2"); var NodeManager = function(newObj){ var pro=this; for(var i in newObj){ //将配置转变为自身属性 pro[i] = newObj[i]; } }; NodeManager.prototype = { showStaus:function(node){ alert(node.name + ":" + this.msg); }, start:function(){ var len = nodes.length, ins = this; //将实例赋值给变量,以便在此方法中能够使用 for(var i = 0; i < len; i++){ var f = function(idx){ setInterval(function(){ ins.showStaus(nodes[idx])},ins.ticks); } f(i); } } } var m = new NodeManager({ ticks:nodeConfig.ticks, msg:nodeConfig.msg }); m.start(); //--> </SCRIPT> </BODY> </HTML> 至此,才终于将程序划上稍显完美的句号。
参考文章: 深入理解JavaScript闭包(closure) 一个js闭包的小例子 js对象属性类型 0
相关文章读者评论发表评论 |

