Improve event service (#15353)

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
孙世军 2021-07-26 12:16:49 +08:00 committed by GitHub
parent 5984175a1f
commit f6801cea57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 39 deletions

View File

@ -1,5 +1,6 @@
import { TestBed } from '@angular/core/testing';
import { EventService } from "./event.service";
import { Subscription } from "rxjs";
describe('EventServiceService', () => {
@ -13,4 +14,18 @@ describe('EventServiceService', () => {
it('should be created', () => {
expect(service).toBeTruthy();
});
it('able to subscribe', () => {
let result: string;
const sub1 = service.subscribe('testEvent', data => {
result = data;
});
expect(sub1 ).toBeTruthy();
expect((sub1 instanceof Subscription)).toEqual(true);
service.publish('testEvent', 'resultString');
sub1.unsubscribe();
expect(result).toEqual('resultString');
});
});

View File

@ -1,54 +1,73 @@
import { Injectable } from '@angular/core';
import { from, Subject } from "rxjs";
import { Subscription } from "rxjs";
@Injectable({
providedIn: "root"
})
export class EventService {
private listeners = {};
private eventsSubject = new Subject();
private events = from(this.eventsSubject);
constructor() {
this.events.subscribe(
({name, args}) => {
if (this.listeners[name]) {
for (let listener of this.listeners[name]) {
listener(...args);
}
}
});
}
subscribe(name: string, listener): any {
if (!this.listeners[name]) {
this.listeners[name] = [];
private _channels: any = [];
/**
* Subscribe to an event topic. Events that get posted to that topic will trigger the provided handler.
*
* @param {string} topic the topic to subscribe to
* @param {function} handler the event handler
* @return A Subscription to unsubscribe
*/
subscribe(topic: string, handler: Function): Subscription {
if (!this._channels[topic]) {
this._channels[topic] = [];
}
this.listeners[name].push(listener);
return {
unsubscribe: () => {
this.doUnsubscribe(name, listener);
}
};
}
doUnsubscribe(name, listener) {
this.listeners[name] = this.listeners[name].filter((v) => {
return v !== listener;
this._channels[topic].push(handler);
return new Subscription(() => {
this.unsubscribe(topic, handler);
});
}
unsubscribe(name, listener?) {
if (this.listeners[name]) {
if (!listener) {
this.listeners[name] = [];
} else {
this.doUnsubscribe(name, listener);
}
/**
* Unsubscribe from the given topic. Your handler will no longer receive events published to this topic.
*
* @param {string} topic the topic to unsubscribe from
* @param {function} handler the event handler
*
*/
private unsubscribe(topic: string, handler: Function = null) {
let t = this._channels[topic];
if (!t) {
// Wasn't found, wasn't removed
return;
}
if (!handler) {
// Remove all handlers for this topic
delete this._channels[topic];
return;
}
// We need to find and remove a specific handler
let i = t.indexOf(handler);
if (i < 0) {
// Wasn't found, wasn't removed
return;
}
t.splice(i, 1);
// If the channel is empty now, remove it from the channel map
if (!t.length) {
delete this._channels[topic];
}
return;
}
publish(name, ...args) {
this.eventsSubject.next({
name,
args
/**
* Publish an event to the given topic.
* @param topic
* @param data
*/
publish(topic: string, data?: any) {
const t = this._channels[topic];
if (!t) {
return;
}
t.forEach((handler: any) => {
handler(data);
});
}
}