Skip to content

Instantly share code, notes, and snippets.

@alexeyraspopov
Last active February 10, 2021 19:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexeyraspopov/e579c0ecc565b800594354f5c9649ac5 to your computer and use it in GitHub Desktop.
Save alexeyraspopov/e579c0ecc565b800594354f5c9649ac5 to your computer and use it in GitHub Desktop.

There is a common pattern to implement an observer/event emitter that returns a subscription handler when a new listener is created. This means subscription handler has direct access to the scope that create the listener. Usually, these observers use arrays or sets to store a list of listeners. Removing a listener means using deletion methods that an array or a set provides. Alternatively, the list of listeners can be implemented as a doubly-linked list. This makes both listener insert and delete operations O(1) instead of array/set's complexity. Obviously, there won't be significant performance gain, but no overhead is better than small overhead.

export default class Signal {
head = null;
tail = null;
subscribe(callback) {
let listener = { callback, prev: null, next: null };
if (this.head == null) {
this.head = listener;
this.tail = listener;
} else {
listener.prev = this.tail;
this.tail.next = listener;
this.tail = listener;
}
return {
dispose: () => {
if (listener === this.head) {
this.head = this.head.next;
if (this.head != null) {
this.head.prev = null;
}
if (listener === this.tail) {
this.tail = null;
}
} else if (listener === this.tail) {
this.tail = this.tail.prev;
this.tail.next = null;
} else {
listener.prev.next = listener.next;
listener.next.prev = listener.prev;
}
},
};
}
publish(data) {
let cursor = this.head;
while (cursor != null) {
cursor.callback.call(null, data);
cursor = cursor.next;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment