js自定义消息机制研究学习(二)--做一些改动,定制自己的消息机制

js自定义消息机制研究学习(二)——做一些改动,定制自己的消息机制

上一篇 js自定义消息机制研究学习(一) ——看百度搜索输入提示 简单研究了一下百度首页的代码。

今天我来尝试修改一下代码,以使它更适合我们实际的研发情况。

首先,我们修改一下代码,让它可读性稍微好一点。(原代码参考上文)

  monitor.js var monitor= (function(){

function bind(b){

var queue = this.__MSG_QS__;

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

function trigger(Y){

var queue = this.__MSG_QS__[Y.type];

if (queue == null) {

return

}

for (var a = 0, X = queue.length; a

queue[a].handler(Y)

}

}

return {

ini: function(X){

X.__MSG_QS__ = {};

X.bind = bind;

X.trigger = trigger;

return X

}

}

})();

好了,现在我们有一个monitor对象了

现在来说说加入我们使用这个对象有可能要应对的情况。

一、将消息直接通知到函数

如果我们要简单监听某个对象里的某个消息,譬如下面代码中这个对象里的sendData消息

  View Code var obj1=monitor.ini({sendData:function(){

this.trigger({type:"sendData",data:"1"});

}});

我们只是想简单的将这个要发送的数据alert一下,代码如下:

  View Code obj1.bind("sendData",{handler:function(data){

alert(data.data);

}});

高兴的事,我们很快写完了。我么可以不要{}呢,也不写handler么?

我们改改monitor,让它能直接将消息发送到函数,对monitor的trigger内的方法做一个简单的更改,如下:

  View Code function trigger(Y){

var queue = this.__MSG_QS__[Y.type];

if (queue == null) {

return

}

for (var a = 0, X = queue.length; a

if(queue[a].handler)

{

queue[a].handler(Y)

}

else

{

queue[a](Y);

}

}

}

这样我们就可以直接将消息发送到函数。

当然,这也会给我们带来一点小小的,因为加了if语句的性能损失。10000000次trigger的一个测试数据:1076(未修改前):1134(修改后)——单位毫秒

一个极端点的更改,我们只想把消息传给函数,不传给对象,那么修改如下:

  monitor 只传函数 var monitor= (function(){

function bind(b){

var queue = this.__MSG_QS__;

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

function trigger(Y){

var queue = this.__MSG_QS__[Y.type];

if (queue == null) {

return

}

for (var a = 0, X = queue.length; a

queue[a](Y);

}

}

return {

ini: function(X){

X.__MSG_QS__ = {};

X.bind = bind;

X.trigger = trigger;

return X

}

}

})();

这样,我们只能bind函数了,这样的方式在一些简单的应用中效果也不错,比如我们用jQuery的bind方法就可以实现很多我们要的效果,为了实现bind函数内this指向消息源头,这里使用call方法就可,代码:

  View Code

这样,我们可以基于一个或者数个复杂的对象做一些扩展开发,就像基于dom的click等事件来实现我们想要的效果一样简单。

但如果涉及多个对象直接互相传递消息,只bind到函数就有点限制。如果不是特殊的需求,不建议用这种方式,最好bind到对象,兼容bind到对象和函数,也会让我们少敲一些handler,因此也是个不错的选择

二、new的对象如何绑定monitor

当我们准备用js面向对象开发时,我们干:

  View Code function base()

{}

var obj=new base();

那么我们想要在new出来对象上使用monitor模式,少一点使用,我们可以monitor.ini(obj);

那么如果大量类似对象要使用monitor模式呢?譬如

  View Code function Person(name)

{

this.name=name;

this.sayHello=function()

{

this.trigger({type:"say",msg:"hi,我是"+this.name})

}

}

我们要创建很多的对象,然后调用他们的sayHello,假设是很多人对不同的对象说话的场景,我们创建一个Person对象就要monitor.ini一下,这种办法很笨

假设你不想修改monitor的代码,你可以这样:

monitor.ini(Person.prototype);

如果你确实想简单写成如下:

monitor.ini(Person);

那么只好修改修改monitor代码了:

首先是ini

360docimg_16_  View Code ini: function(X){

if(Object.prototype.toString.call(X)=="[object Function]")

{

var proto=X.prototype;

proto.bind = bind;

proto.trigger = trigger;

}

X.bind = bind;

X.trigger = trigger;

return X

}

我去掉了__MSG_QS__ 这个的初始化,因为如果在prototype上绑定__MSG_QS__ 属性的话,每一个bind都会bind到所有对象上,这不是我们的本意,就例如我们希望的是每一个Person说的话,只能由听他说话的人收听到。实现这样的效果还需要在bind,trigger时做一些修改,如下:

360docimg_18_  bind

360docimg_20_  trigger function trigger(Y){

var qs=this.__MSG_QS__ || {};

var queue= qs[Y.type] || [];

for (var a = 0, X = queue.length; a

if(queue[a].handler)

{

queue[a].handler(Y)

}

else

{

queue[a].call(this,Y);;

}

}

}

***PS:我把if (queue == null) {return }也去掉了

三、如何绑定类消息

这里的类消息是这样的一种需求,比如接上例,我们要用一个logger记录所有Person讲的话(sayHello()),难道我们创建一百个Person,就要调用一百次bind么?假如只有一处代码才能new Person()那还好说,不会增加我们多少的代码量。但你的new Person已经洒落到代码各处,到处都是。OMG。怎么办?

首先,再剽窃一个jQuery的命名:live,在monitor中加入live代码如下:

360docimg_22_  live function live(b)

{

var queue = this.prototype.__STATIC_MSG_QS__;

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

这段代码与bind区别不大,唯一的区别是它这里使用了this.prototype.__STATIC_MSG_QS__ 而不是this.__MSG_QS__ 我们用__STATIC_MSG_QS__ 来存储类级别的消息队列

所以它是面向function对象的,把ini修改如下

360docimg_24_  ini return {

ini: function(X){

if(Object.prototype.toString.call(X)=="[object Function]")

{

var proto=X.prototype;

proto.__STATIC_MSG_QS__={};

proto.bind = bind;

proto.trigger = trigger;

X.live=live;

}

X.bind = bind;

X.trigger = trigger;

return X

}

}

如果ini的是function,我们就再function上面绑定了live方法,并且在prototype上增加了__STATIC_MSG_QS__

我们还需要修改一下trigger

360docimg_26_  trigger function trigger(Y){

var queue =[];

var qs=this.__MSG_QS__ || {};

var sqs=this.__STATIC_MSG_QS__|| {};

queue= queue.concat(qs[Y.type] || []);

queue= queue.concat(sqs[Y.type] || []);

for (var a = 0, X = queue.length; a

if(queue[a].handler)

{

queue[a].handler(Y)

}

else

{

queue[a].call(this,Y);

}

}

}

增加了一些trigger的负担,queue不再直接指向this.__MSG_QS__中获取(queue=this.__MSG_QS__会使两者指向同一内存地址),因为这样如果修改queue变量会直接修改掉__MSG_QS__队列中的值,在这里用了两次concat分别拷贝了对象消息监听者和类消息接听者。

ok,现在我们可以一下就监听所有Person对象的消息了,代码如下:

Person.live("say",{handler: function(data){

//logger

});复制代码

搞定,准备洗洗睡吧!

想要使用类似monitor的人,根据自己的实际需求定制一下。比如你想在监听函数里调用消息源,可以把trigger中queue[a].handler(Y)修改为queue[a].handler(Y,this)等等

修改后的monitor

360docimg_28_  View Code var monitor= (function(){

function bind(b){

var queue = this.__MSG_QS__=this.__MSG_QS__ || {};

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

function live(b)

{

var queue = this.prototype.__STATIC_MSG_QS__;

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

function trigger(Y){

var queue =[];

var qs=this.__MSG_QS__ || {};

var sqs=this.__STATIC_MSG_QS__|| {};

queue= queue.concat(qs[Y.type] || []);

queue= queue.concat(sqs[Y.type] || []);

for (var a = 0, X = queue.length; a

if(queue[a].handler)

{

queue[a].handler(Y,this)

}

else

{

queue[a].call(this,Y,this);

}

}

}

return {

ini: function(X){

if(Object.prototype.toString.call(X)=="[object Function]")

{

var proto=X.prototype;

proto.__STATIC_MSG_QS__={};

proto.bind = bind;

proto.trigger = trigger;

X.live=live;

}

X.bind = bind;

X.trigger = trigger;

return X

}

}

})();

它多了如下一些特性:

1. 可以直接用一个函数侦听消息

2. 可以将function注册为monitor,然后所有function new出来的对象都将自动绑定了monitor

3. 为function增加了live方法,可以方便侦听所有new对象的事件

4. 将消息源作为第二个参数传给了方法。

附:

这只是简单的一些修改扩展,如果你没有这些需要,简单原始的monitor就非常简洁高效,足够应付一些简单的建模。

实际中我用的类似的monitor模式,不是只有ini的一个{ini:function()}对象,而是一个有bind,trigger,unbind,live,die等方法的function对象,使用继承的方式(比如jQuery.extend)来为{}或new的对象绑定monitor的模式。因此增加了许多的条件判断,性能上要比本文的monitor差一些。

这里的代码都是写本文时随手写的,难免有误,欢迎指正。

js自定义消息机制研究学习(二)——做一些改动,定制自己的消息机制

上一篇 js自定义消息机制研究学习(一) ——看百度搜索输入提示 简单研究了一下百度首页的代码。

今天我来尝试修改一下代码,以使它更适合我们实际的研发情况。

首先,我们修改一下代码,让它可读性稍微好一点。(原代码参考上文)

  monitor.js var monitor= (function(){

function bind(b){

var queue = this.__MSG_QS__;

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

function trigger(Y){

var queue = this.__MSG_QS__[Y.type];

if (queue == null) {

return

}

for (var a = 0, X = queue.length; a

queue[a].handler(Y)

}

}

return {

ini: function(X){

X.__MSG_QS__ = {};

X.bind = bind;

X.trigger = trigger;

return X

}

}

})();

好了,现在我们有一个monitor对象了

现在来说说加入我们使用这个对象有可能要应对的情况。

一、将消息直接通知到函数

如果我们要简单监听某个对象里的某个消息,譬如下面代码中这个对象里的sendData消息

  View Code var obj1=monitor.ini({sendData:function(){

this.trigger({type:"sendData",data:"1"});

}});

我们只是想简单的将这个要发送的数据alert一下,代码如下:

  View Code obj1.bind("sendData",{handler:function(data){

alert(data.data);

}});

高兴的事,我们很快写完了。我么可以不要{}呢,也不写handler么?

我们改改monitor,让它能直接将消息发送到函数,对monitor的trigger内的方法做一个简单的更改,如下:

  View Code function trigger(Y){

var queue = this.__MSG_QS__[Y.type];

if (queue == null) {

return

}

for (var a = 0, X = queue.length; a

if(queue[a].handler)

{

queue[a].handler(Y)

}

else

{

queue[a](Y);

}

}

}

这样我们就可以直接将消息发送到函数。

当然,这也会给我们带来一点小小的,因为加了if语句的性能损失。10000000次trigger的一个测试数据:1076(未修改前):1134(修改后)——单位毫秒

一个极端点的更改,我们只想把消息传给函数,不传给对象,那么修改如下:

  monitor 只传函数 var monitor= (function(){

function bind(b){

var queue = this.__MSG_QS__;

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

function trigger(Y){

var queue = this.__MSG_QS__[Y.type];

if (queue == null) {

return

}

for (var a = 0, X = queue.length; a

queue[a](Y);

}

}

return {

ini: function(X){

X.__MSG_QS__ = {};

X.bind = bind;

X.trigger = trigger;

return X

}

}

})();

这样,我们只能bind函数了,这样的方式在一些简单的应用中效果也不错,比如我们用jQuery的bind方法就可以实现很多我们要的效果,为了实现bind函数内this指向消息源头,这里使用call方法就可,代码:

  View Code

这样,我们可以基于一个或者数个复杂的对象做一些扩展开发,就像基于dom的click等事件来实现我们想要的效果一样简单。

但如果涉及多个对象直接互相传递消息,只bind到函数就有点限制。如果不是特殊的需求,不建议用这种方式,最好bind到对象,兼容bind到对象和函数,也会让我们少敲一些handler,因此也是个不错的选择

二、new的对象如何绑定monitor

当我们准备用js面向对象开发时,我们干:

  View Code function base()

{}

var obj=new base();

那么我们想要在new出来对象上使用monitor模式,少一点使用,我们可以monitor.ini(obj);

那么如果大量类似对象要使用monitor模式呢?譬如

  View Code function Person(name)

{

this.name=name;

this.sayHello=function()

{

this.trigger({type:"say",msg:"hi,我是"+this.name})

}

}

我们要创建很多的对象,然后调用他们的sayHello,假设是很多人对不同的对象说话的场景,我们创建一个Person对象就要monitor.ini一下,这种办法很笨

假设你不想修改monitor的代码,你可以这样:

monitor.ini(Person.prototype);

如果你确实想简单写成如下:

monitor.ini(Person);

那么只好修改修改monitor代码了:

首先是ini

360docimg_16_  View Code ini: function(X){

if(Object.prototype.toString.call(X)=="[object Function]")

{

var proto=X.prototype;

proto.bind = bind;

proto.trigger = trigger;

}

X.bind = bind;

X.trigger = trigger;

return X

}

我去掉了__MSG_QS__ 这个的初始化,因为如果在prototype上绑定__MSG_QS__ 属性的话,每一个bind都会bind到所有对象上,这不是我们的本意,就例如我们希望的是每一个Person说的话,只能由听他说话的人收听到。实现这样的效果还需要在bind,trigger时做一些修改,如下:

360docimg_18_  bind

360docimg_20_  trigger function trigger(Y){

var qs=this.__MSG_QS__ || {};

var queue= qs[Y.type] || [];

for (var a = 0, X = queue.length; a

if(queue[a].handler)

{

queue[a].handler(Y)

}

else

{

queue[a].call(this,Y);;

}

}

}

***PS:我把if (queue == null) {return }也去掉了

三、如何绑定类消息

这里的类消息是这样的一种需求,比如接上例,我们要用一个logger记录所有Person讲的话(sayHello()),难道我们创建一百个Person,就要调用一百次bind么?假如只有一处代码才能new Person()那还好说,不会增加我们多少的代码量。但你的new Person已经洒落到代码各处,到处都是。OMG。怎么办?

首先,再剽窃一个jQuery的命名:live,在monitor中加入live代码如下:

360docimg_22_  live function live(b)

{

var queue = this.prototype.__STATIC_MSG_QS__;

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

这段代码与bind区别不大,唯一的区别是它这里使用了this.prototype.__STATIC_MSG_QS__ 而不是this.__MSG_QS__ 我们用__STATIC_MSG_QS__ 来存储类级别的消息队列

所以它是面向function对象的,把ini修改如下

360docimg_24_  ini return {

ini: function(X){

if(Object.prototype.toString.call(X)=="[object Function]")

{

var proto=X.prototype;

proto.__STATIC_MSG_QS__={};

proto.bind = bind;

proto.trigger = trigger;

X.live=live;

}

X.bind = bind;

X.trigger = trigger;

return X

}

}

如果ini的是function,我们就再function上面绑定了live方法,并且在prototype上增加了__STATIC_MSG_QS__

我们还需要修改一下trigger

360docimg_26_  trigger function trigger(Y){

var queue =[];

var qs=this.__MSG_QS__ || {};

var sqs=this.__STATIC_MSG_QS__|| {};

queue= queue.concat(qs[Y.type] || []);

queue= queue.concat(sqs[Y.type] || []);

for (var a = 0, X = queue.length; a

if(queue[a].handler)

{

queue[a].handler(Y)

}

else

{

queue[a].call(this,Y);

}

}

}

增加了一些trigger的负担,queue不再直接指向this.__MSG_QS__中获取(queue=this.__MSG_QS__会使两者指向同一内存地址),因为这样如果修改queue变量会直接修改掉__MSG_QS__队列中的值,在这里用了两次concat分别拷贝了对象消息监听者和类消息接听者。

ok,现在我们可以一下就监听所有Person对象的消息了,代码如下:

Person.live("say",{handler: function(data){

//logger

});复制代码

搞定,准备洗洗睡吧!

想要使用类似monitor的人,根据自己的实际需求定制一下。比如你想在监听函数里调用消息源,可以把trigger中queue[a].handler(Y)修改为queue[a].handler(Y,this)等等

修改后的monitor

360docimg_28_  View Code var monitor= (function(){

function bind(b){

var queue = this.__MSG_QS__=this.__MSG_QS__ || {};

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

function live(b)

{

var queue = this.prototype.__STATIC_MSG_QS__;

if (!queue[b]) {

queue[b] = []

}

for (var a = 1, X = arguments.length, Y; a

queue[b].push(arguments[a])

}

}

function trigger(Y){

var queue =[];

var qs=this.__MSG_QS__ || {};

var sqs=this.__STATIC_MSG_QS__|| {};

queue= queue.concat(qs[Y.type] || []);

queue= queue.concat(sqs[Y.type] || []);

for (var a = 0, X = queue.length; a

if(queue[a].handler)

{

queue[a].handler(Y,this)

}

else

{

queue[a].call(this,Y,this);

}

}

}

return {

ini: function(X){

if(Object.prototype.toString.call(X)=="[object Function]")

{

var proto=X.prototype;

proto.__STATIC_MSG_QS__={};

proto.bind = bind;

proto.trigger = trigger;

X.live=live;

}

X.bind = bind;

X.trigger = trigger;

return X

}

}

})();

它多了如下一些特性:

1. 可以直接用一个函数侦听消息

2. 可以将function注册为monitor,然后所有function new出来的对象都将自动绑定了monitor

3. 为function增加了live方法,可以方便侦听所有new对象的事件

4. 将消息源作为第二个参数传给了方法。

附:

这只是简单的一些修改扩展,如果你没有这些需要,简单原始的monitor就非常简洁高效,足够应付一些简单的建模。

实际中我用的类似的monitor模式,不是只有ini的一个{ini:function()}对象,而是一个有bind,trigger,unbind,live,die等方法的function对象,使用继承的方式(比如jQuery.extend)来为{}或new的对象绑定monitor的模式。因此增加了许多的条件判断,性能上要比本文的monitor差一些。

这里的代码都是写本文时随手写的,难免有误,欢迎指正。


相关文章

  • 面向对象程序设计历史及发展
  • 面向对象程序设计的历史及发展 姓名:郭一恒 班级:0901 学号:[1**********]14 自从计算机发展以来,程序设计的方法为了适应越来越复杂的程序设计的需要而发生了急剧的变化.计算机刚问世时.程序设计是通过计算机的控制板用二进制机 ...查看


  • 中心数据交换平台建设方案
  • XX 省电子政务系统 数据交换平台 国际商业机器中国有限公司 2005.5 目 录: 1 概述 数据交换共享平台是协作式电子政务应用平台(包括政府职能部门之间的电子协作.政府与公众/企事业单位的服务管理等)的核心基础服务模块,负责实现跨系统 ...查看


  • AWSCTO对过去十年的经验总结
  • AWS CTO对过去十年的经验总结 – 十条军规 AWS(Amazon Web Service) 开始于 2006 年 3 月 14 日 Amazon S3 的发布,距今已有十年时间.回首过去十年,我们在构建和运营 AWS 云计算服务中积累 ...查看


  • 新手上路SAP
  • SAP R/3系统介绍 第1章 用SAP R/3 开展经营项目 如果在SAP 领域中有一个词用得比SAP本身或R/3 还要频繁的话,这个词就是经营(business). 经营是整个SAP战略:(软件.服务.功能.评价.任务和目标等)的核心. ...查看


  • 实时性改善措施
  • 一.实时操作系统定义 1.实时操作系统 实时操作系统(RTOS )是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的操作系统 ...查看


  • [软件工程导论]考试夹带
  • 1.软件危机的概念:软件危机是指在计算机软件的开发和维护过程中所遇到的一系 列严重的问题. 2.产生软件危机的原因:一方面与软件本身的特点有关,另一方面也和软件开发与 维护的方法不正确有关. 3.软件工程的定义:是指导计算机软件开发和维护的 ...查看


  • 信息安全技术与实施-第五章
  • 第五章 数字身份认证 5.1 信息认证技术 5.1.1 信息认证技术概述 边界安全(防火墙-网络安全隔离卡与线路选择器-安全隔离与信息交换产品) 通信安全(安全路由器) 身份鉴别与访问控制(智能卡COS ) 数据安全(数据备份与恢复产品) ...查看


  • 面向服务的战场态势感知与协同技术研究
  • 第2期2012 年4月 Journal of CAEIT Vol.7No.2Apr.2012 檵檵0 共用态势图(COP )简称态势图,是军事指挥部门了解战场态势的主要手段,是广泛的战场态势感知系统.服务和应用的一个关键部分,是服务于决策制 ...查看


  • 联通短信定购流程 .
  • 联通短信定购流程 目前,联通短信定购流程如下: 第一步 用户上行 用户按照要求书写信息内容并提交到指定号码. 例如:用户填写3611发送到9929. 第二步 联通验证 联通检查用户上行信息,并匹配业务代码.如果匹配成功,联通将会直接将该业务 ...查看


热门内容