说在前面:写js时候,当一个变量一旦发生变化,就自动执行相应的程序,而不用手动执行,js-signals可以很方便的解决这个问题。
一.js-signals简介
js-signals是用于在JavaScript中的软件组件之间定义和触发基于事件的消息的库,它是一个类似于Event Emitter / Dispatcher或Pub / Sub系统的事件/消息系统,主要区别在于每个事件类型都有自己的控制器功能,而不依赖于字符串来广播/订阅事件,它还具有通常在其他系统上不可用的一些额外功能。
本人因为项目需要,寻找关于js-signals的学习资料,发现都是英文的,所以自己写个学习小结,也希望帮助后来需要学习的同学们。后面第三部分用户指南,会详细介绍js-signals的具体用法。
github:https://github.com/millermedeiros/js-signals
example:http://www.javascriptoo.com/js-signals
官方使用详解:https://millermedeiros.github.io/js-signals/
官方documentation:https://millermedeiros.github.io/js-signals/docs/
作者博客:http://blog.millermedeiros.com/
http://blog.millermedeiros.com/js-signals-custom-eventmessaging-system-for-javascript/
二.不同设计模式实现之间的比较
命名约定
建议您始终以过去时态命名信号。这个惯例是基于AS3-Signals的建议,其背后的原因是避免与常规属性混淆并保持一致性。尝试组合多个单词,如果您尝试描述的事件没有过去时的形式或如果您有命名冲突。
三.用法示例
1.引入js-signals:
node.js
var Signal = require('signals'); var mySignal = new Signal();
AMD
define(['signals'], function(Signal){ var mySignal = new Signal(); });
Browser globals
2.声明Signal对象:
//store local reference for brevity var Signal = signals.Signal;
3.用户自定义对象:
//custom object that dispatch signals var myObject = { started : new Signal(), //past tense is the recommended signal naming convention stopped : new Signal() };
4.添加/调度/删除单个监听器(Single Listener):给started 信号绑定事件 onstarted(function)
function onStarted(param1, param2){ alert(param1 + param2); } myObject.started.add(onStarted); //添加监听器 myObject.started.dispatch('foo', 'bar'); //给 started 信号绑定的事件传送参数(param1, param2),即('foo', 'bar') myObject.started.remove(onStarted); //删除监听器
5.添加/调度/删除多个监听器(Multiple Listeners)
function onStopped(){ alert('stopped'); } function onStopped2(){ alert('stopped listener 2'); } myObject.stopped.add(onStopped); myObject.stopped.add(onStopped2); myObject.stopped.dispatch(); myObject.stopped.removeAll(); //remove all listeners of the `stopped` signal
6.多次调度(Multiple Dispatches),也就是多次运行handler
var i = 0; myObject.started.add(function(){ i += 1; alert(i); }); myObject.started.dispatch(); //will alert 1,调度一次 myObject.started.dispatch(); //will alert 2,调度两次
7.Multiple Dispatches + addOnce()
var i = 0; myObject.started.addOnce(function(){ i += 1; alert(i); }); myObject.started.dispatch(); //will alert 1 myObject.started.dispatch(); //nothing happens
8.启用/禁用信号(Enable/Disable Signal)
var i = 0; myObject.started.add(function(){ i += 1; alert(i); }); myObject.started.dispatch(); //will alert 1 myObject.started.active = false; myObject.started.dispatch(); //nothing happens myObject.started.active = true; myObject.started.dispatch(); //will alert 2
9.Stop/Halt Propagation(停止/终止 传播)
方法一:直接调用signal.halt()停止
myObject.started.add(function(){ myObject.started.halt(); //防止下一个listener在队列中被执行
});
myObject.started.add(function(){ alert('second listener'); //不会被调用,因为第一个监听器停止传播
});
myObject.started.dispatch();
方法二:通过返回值 false 停止
myObject.started.add(function(){ return false; //if handler returns `false` will also stop propagation }); myObject.started.add(function(){ alert('second listener'); //won't be called since first listener stops propagation }); myObject.started.dispatch();
10.设置侦听器处理程序的执行上下文
var foo = 'bar'; var obj = { foo : 10 }; function handler1(){ alert(this.foo); } function handler2(){ alert(this.foo); } //note that you cannot add the same handler twice to the same signal without removing it first myObject.started.add(handler1); //默认执行上下文,参数是windows.foo myObject.started.add(handler2, obj); //设置不同的上下文,传入obj.foo myObject.started.dispatch(); //first handler will alert "bar", second will alert "10".
11.设置监听器的优先级
var handler1 = function(){ alert('foo'); }; var handler2 = function(){ alert('bar'); }; myObject.started.add(handler1); //默认优先级为0,add(handler,context,priority) myObject.started.add(handler2, null, 2); //设置优先级为2,'handler2' 将比'handler1' 提早运行 myObject.started.dispatch(); //will alert "bar" than "foo"
12.启用/禁用单个SignalBinding
var handler1 = function(){ alert('foo bar'); }; var handler2 = function(){ alert('lorem ipsum'); }; var binding1 = myObject.started.add(handler1); //methods `add()` and `addOnce()` returns a SignalBinding object myObject.started.add(handler2); myObject.started.dispatch(); //execute handler1 , will alert "foo bar" than "lorem ipsum" binding1.active = false; //disable a single binding myObject.started.dispatch(); //will alert "lorem ipsum" binding1.active = true; myObject.started.dispatch(); //will alert "foo bar" than "lorem ipsum"
13.手动执行信号处理程序:不用signal.dispatch(),用 SignalBinding.execute()
var handler = function(){ alert('foo bar'); }; var binding = myObject.started.add(handler); //methods `add()` and `addOnce()` returns a SignalBinding object binding.execute(); //will alert "foo bar"
14.检索匿名监听器:本人觉得可能是系统默认绑定的handler
var binding = myObject.started.add(function(){ alert('foo bar'); }); var handler = binding.getListener(); //reference to the anonymous function
15.删除/分离匿名监听器
var binding = myObject.started.add(function(){ alert('foo bar'); }); myObject.started.dispatch(); //will alert "foo bar" binding.detach();//分离监听器 alert(binding.isBound()); //will alert `false` myObject.started.dispatch(); //nothing happens
16.检查绑定是否只执行一次
var binding1 = myObject.started.add(function(){ alert('foo bar'); }); var binding2 = myObject.started.addOnce(function(){ alert('foo bar'); }); alert(binding1.isOnce()); //alert "false" alert(binding2.isOnce()); //alert "true"
17.更改监听器执行上下文
var foo = 'bar'; var obj = { foo : "it's over 9000!" }; var binding = myObject.started.add(function(){ alert(this.foo);//this 指的是 windows,也就是说默认绑定的上下文环境是windows }); myObject.started.dispatch(); //will alert "bar" binding.context = obj; myObject.started.dispatch(); //will alert "it's over 9000!"
18.将默认参数添加到信号调度
var binding = myObject.started.add(function(a, b, c){ alert(a +' '+ b +' '+ c); }); binding.params = ['lorem', 'ipsum']; //set default parameters of the binding myObject.started.dispatch('dolor'); //will alert "lorem ipsum dolor"
类似于:
var binding = myObject.started.add(function(a, b, c){ alert(a +' '+ b +' '+ c); }); myObject.started.dispatch('lorem', 'ipsum','dolor'); //will alert "lorem ipsum dolor"
19.检查信号是否绑定某个特定的监听器
function onStart(a){ console.log(a); } myObject.started.add(onStart); myObject.started.has(onStart); // true
20.记住以前分派的值/忘记值
myObject.started.memorize = true; // default is false myObject.started.dispatch('foo'); // add()/addOnce() will automatically fire listener if signal was dispatched before // will log "foo" since it keeps record of previously dispatched values myObject.started.addOnce(console.log, console); // dispatching a new value will overwrite the "memory" myObject.started.dispatch('lorem'); // will log "lorem" myObject.started.addOnce(console.log, console); myObject.started.forget(); // forget previously dispatched values (reset signal state) myObject.started.addOnce(console.log, console); // won't log till next dispatch (since it "forgot") myObject.started.dispatch('bar'); // log "bar"
21.一次性监听多个信号见 CompoundSignal repository
四.库函数解析
1. signals ,Signals命名空间
2.Signal类
var mySignal = new Signal();//mySignal 是 Signals 类的一个对象。
Signal类属性
mySignal.active = false/true; //该信号监听调度是否停止,默认true可用 mySignal.memorize = false/true; //该信号是否记录之前的调度参数并且自动执行,默认为false不记录 mySignal.VERSION = ''; //记录当前信号的版本
Signals类方法
add();添加监听器
//add(listener, listenerContext, priority); //listener 属于function类型,是信号操作函数 //listenerContext 属于object类型,是监听器的执行上下文环境,可选 //priority 属于Number类型,是该监听器的优先级,高优先级的先执行,默认为0,可选
//返回值是 SignalBinding 类型
mySignal.add(listener, listenerContext, priority);
addOnce();添加一次性监听器,运行完一次即可自动remove
//add(listener, listenerContext, priority); //listener 属于function类型,是信号操作函数 //listenerContext 属于object类型,是监听器的执行上下文环境,可选 //priority 属于Number类型,是该监听器的优先级,高优先级的先执行,默认为0,可选 //返回值是 SignalBinding 类型 mySignal.addOnce(listener, listenerContext, priority);
dispatch();调度/广播信号到所有监听器,加入队列,即让监听器运行
//dispatch(params),paras可选 mySignal.dispatch();
dispose();删除所有相关的信号对象和绑定,无返回值
mySignal.dispose();
forget();清除记忆的arguments,无返回值
mySignal.forget();
getNumListeners();返回该信号绑定的监听器的个数
mySignal.getNumListeners();
halt();停止分发事件,blocking the dispatch to next listeners on the queue.
mySignal.halt();
has();检查该信号是否与特定监听器绑定
//listener ; 监听器的执行函数 //context ;执行的上下文环境,可选 // 返回值为true 或者 false mySignal.has(listener, context);
remove();删除监听器
//listener ; 监听器的执行函数 //context ;执行的上下文环境,可选 //返回监听器的执行函数handler mySignal.remove(listener, context);
removeAll();删除该信号的所有监听器
mySignal.removeAll();
toString();返回当前的object的
3.SignalBinding类
var binding = myObject.started.add(function(){ alert('foo bar'); });
等同于
//SignalBinding(signal, listener, isOnce, listenerContext(可选), priority(可选))
var binding = new SignalBinding(myObject.started, handler, false, myObject, 0) function handler(){ alert('foo bar'); }
SignalBinding类属性
binding.active = false/true; //该信号监听调度是否停止,默认true可用 binding.context = object; //绑定的上下文环境 binding.params = ''; //默认在Signal.dispatch()期间传递给监听器的参数
SignalBinding类方法
binding.detach();//分离信号和监听器 binding.execute();//手动执行 binding.getListener();//返回绑定的特定监听函数 binding.getSignal();//返回绑定的特定信号量 binding.isBound();//判断是否绑定成功,true or false binding.isOnce();//判断是否是一次绑定 binding.toString()//转换为字符串
函数简易查询索引地址:https://millermedeiros.github.io/js-signals/docs/symbolindex.html
五.应用实例
test signal