Last active
October 8, 2015 06:28
-
-
Save lynxerzhang/3291503 to your computer and use it in GitHub Desktop.
modify RichardLord's Signal version @see https://github.com/richardlord/Signals
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package | |
{ | |
import flash.utils.Dictionary; | |
/** | |
* modified RichardLord's Signal version | |
* @see https://github.com/richardlord/Signals | |
*/ | |
public class Signals{ | |
private var nodeDict:Dictionary; | |
private var head:ListenerNode; | |
private var tail:ListenerNode; | |
private var cacheHead:ListenerNode; | |
private var cacheTail:ListenerNode; | |
private var nodePool:ListenerNodePool; | |
/** | |
* construct Signal | |
*/ | |
public function Signals():void{ | |
nodePool = new ListenerNodePool(); | |
nodeDict = new Dictionary(false); | |
} | |
/** | |
* dispatch to all observer | |
*/ | |
public function dispatch(...args):void{ | |
dispatching = true; | |
if(head){ | |
for(var node:ListenerNode = head; node; node = node.next){ | |
var fun:Function = node.listener; | |
if(node.executeOnce){ | |
remove(fun); | |
} | |
fun.apply(null, args); | |
} | |
} | |
dispatching = false; | |
//the remove operation complete | |
nodePool.release(); | |
//the add operation complete | |
if(cacheHead){ | |
if(!head){ | |
head = cacheHead; | |
tail = cacheTail; | |
} | |
else{ | |
tail.next = cacheHead; | |
cacheHead.prev = tail; | |
tail = cacheTail; | |
} | |
} | |
cacheHead = null; | |
cacheTail = null; | |
} | |
/*create a execute function*/ | |
public function add(fun:Function, executeOnce:Boolean = false):void{ | |
if(nodeDict[fun]){ | |
return; | |
} | |
var node:ListenerNode = nodePool.get(); | |
node.listener = fun; | |
node.executeOnce = executeOnce; | |
nodeDict[fun] = node; | |
addNode(node); | |
} | |
/*remove all node*/ | |
public function removeAll():void{ | |
nodePool.remove(); | |
for(var fun:* in nodeDict){ | |
delete nodeDict[fun]; | |
} | |
//nodeDict = new Dictionary(false); | |
head = null; | |
tail = null; | |
cacheHead = null; | |
cacheTail = null; | |
} | |
/*remove specfied fun*/ | |
public function remove(fun:Function):void{ | |
var node:ListenerNode = nodeDict[fun]; | |
if(!node){ | |
return; | |
} | |
if(node == head){ | |
head = head.next; | |
} | |
if(node == tail){ | |
tail = tail.next; | |
} | |
if(node == cacheHead){ | |
cacheHead = cacheHead.next; | |
} | |
if(node == cacheTail){ | |
cacheTail = cacheTail.next; | |
} | |
if(node.next){ | |
node.next.prev = node.prev; | |
} | |
if(node.prev){ | |
node.prev.next = node.next; | |
} | |
delete nodeDict[fun]; | |
if(dispatching){ | |
nodePool.cache(node); | |
} | |
else{ | |
nodePool.dispose(node); | |
} | |
} | |
private var dispatching:Boolean = false; | |
private function addNode(node:ListenerNode):void{ | |
if(dispatching){ | |
if(!cacheHead){ | |
cacheHead = cacheTail = node; | |
} | |
else{ | |
node.prev = cacheTail; | |
cacheTail.next = node; | |
cacheTail = node; | |
} | |
} | |
else{ | |
if(!head){ | |
tail = head = node; | |
} | |
else{ | |
node.prev = tail; | |
tail.next = node; | |
tail = node; | |
} | |
} | |
} | |
} | |
} | |
/*node pool*/ | |
internal class ListenerNodePool | |
{ | |
/*tail*/ | |
private var tail:ListenerNode; | |
/*cache tail*/ | |
private var cacheTail:ListenerNode; | |
/*get the idle node*/ | |
public function get():ListenerNode{ | |
if(tail){ | |
var node:ListenerNode = tail; | |
tail = tail.prev; | |
return node; | |
} | |
else{ | |
return new ListenerNode(); | |
} | |
} | |
/*dispose specfied node*/ | |
public function dispose(node:ListenerNode):void{ | |
node.prev = tail; | |
node.next = null; | |
node.listener = null; | |
node.executeOnce = false; | |
tail = node; | |
} | |
/*cache specfied node and free in the dispatching end state*/ | |
public function cache(node:ListenerNode):void{ | |
//node.listener = null; | |
//node.next = null; | |
node.executeOnce = false; | |
node.prev = cacheTail; | |
cacheTail = node; | |
} | |
/*release all cache node and add to tail node for save performance*/ | |
public function release():void{ | |
while(cacheTail != null){ | |
var node:ListenerNode = cacheTail; | |
node.next = null; | |
node.listener = null; | |
cacheTail = cacheTail.prev; | |
node.prev = tail; | |
tail = node; | |
} | |
} | |
/*gc the cache list*/ | |
public function remove():void{ | |
release(); | |
cacheTail = null; | |
tail = null; | |
} | |
} | |
/*node*/ | |
internal class ListenerNode | |
{ | |
/*next data point*/ | |
public var next:ListenerNode; | |
/*prev data point*/ | |
public var prev:ListenerNode; | |
/*listener reference*/ | |
public var listener:Function; | |
/*whether run once and auto remove from signal*/ | |
public var executeOnce:Boolean; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment