Compare commits

...

5 Commits

3 changed files with 91 additions and 27 deletions

8
package-lock.json generated
View File

@ -1,13 +1,13 @@
{ {
"name": "@hibas123/utils", "name": "@hibas123/utils",
"version": "2.0.0", "version": "2.1.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"typescript": { "typescript": {
"version": "3.3.3333", "version": "3.5.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
"integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==", "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
"dev": true "dev": true
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@hibas123/utils", "name": "@hibas123/utils",
"version": "2.0.2", "version": "2.1.1",
"description": "Different Utilities, that are not worth own packages", "description": "Different Utilities, that are not worth own packages",
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",
@ -16,12 +16,13 @@
"type": "git" "type": "git"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^3.3.3333" "typescript": "^3.5.3"
}, },
"files": [ "files": [
"src/",
"lib/", "lib/",
"tsconfig.json", "tsconfig.json",
"readme.md" "readme.md"
], ],
"private": false "private": false
} }

View File

@ -19,41 +19,86 @@ export type ObservableInterface<T> = {
subscribeCollect: (callback: ObserverCallbackCollect<T>) => void; subscribeCollect: (callback: ObserverCallbackCollect<T>) => void;
}; };
const ClosedSymbol = Symbol("Observable Closed");
const LastValueSymbol = Symbol("Observable LastValue");
export default class Observable<T = any> { export default class Observable<T = any> {
private subscriber: ObserverCallback<T>[] = []; private subscriber: ObserverCallback<T>[] = [];
private subscriberCollect: ObserverCallbackCollect<T>[] = []; private subscriberCollect: ObserverCallbackCollect<T>[] = [];
private events: T[] = []; private events: T[] = [];
private timeout: number | undefined = undefined; private timeout: number | undefined = undefined;
// Use symbol to make sure this property cannot be changed from the outside
private [ClosedSymbol] = false;
private [LastValueSymbol]: T | undefined = undefined;
get lastValue() {
return this[LastValueSymbol];
}
get closed() {
return this[ClosedSymbol];
}
constructor(private collect_intervall: number = 100) { } constructor(private collect_intervall: number = 100) { }
/**
* Subscribe to changes
* @param callback Callback called once a value is available
*/
subscribe(callback: ObserverCallback<T>) {
if (this[ClosedSymbol])
throw new Error("Observable is closed!");
let oldcb = this.subscriber.find(e => e === callback);
if (!oldcb)
this.subscriber.push(callback)
}
/**
* Unsubscribe specified callback. After that, it will be discarded.
* @param callback The callback originally subscribed
*/
unsubscribe(callback: ObserverCallback<T> | ObserverCallbackCollect<T>) {
if (this[ClosedSymbol])
return;
let idx = this.subscriber.findIndex(e => e === callback);
if (idx >= 0) {
this.subscriber.splice(idx, 1);
} else {
idx = this.subscriberCollect.findIndex(e => e === callback);
if (idx >= 0)
this.subscriberCollect.splice(idx, 1);
}
}
/**
* Subscribe for a collection of changes
* @param callback Callback called once a or some values are available.
*/
subscribeCollect(callback: ObserverCallbackCollect<T>) {
if (this[ClosedSymbol])
throw new Error("Observable is closed!");
let oldcb = this.subscriberCollect.find(e => e === callback);
if (!oldcb)
this.subscriberCollect.push(callback)
}
/** /**
* Creates Public API with subscribe and unsubscribe * Creates Public API with subscribe and unsubscribe
* *
* @returns {object} * @returns {object}
*/ */
getPublicApi(): ObservableInterface<T> { getPublicApi(): ObservableInterface<T> {
if (this[ClosedSymbol])
throw new Error("Observable is closed!");
return { return {
subscribe: (callback: ObserverCallback<T>) => { subscribe: (callback: ObserverCallback<T>) => this.subscribe(callback),
let oldcb = this.subscriber.find(e => e === callback); unsubscribe: (callback: ObserverCallback<T> | ObserverCallbackCollect<T>) => this.unsubscribe(callback),
if (!oldcb) subscribeCollect: (callback: ObserverCallbackCollect<T>) => this.subscribeCollect(callback)
this.subscriber.push(callback)
},
unsubscribe: (callback: ObserverCallback<T> | ObserverCallbackCollect<T>) => {
let idx = this.subscriber.findIndex(e => e === callback);
if (idx >= 0) {
this.subscriber.splice(idx, 1);
} else {
idx = this.subscriberCollect.findIndex(e => e === callback);
if (idx >= 0)
this.subscriberCollect.splice(idx, 1);
}
},
subscribeCollect: (callback: ObserverCallbackCollect<T>) => {
let oldcb = this.subscriberCollect.find(e => e === callback);
if (!oldcb)
this.subscriberCollect.push(callback)
}
} }
} }
@ -62,6 +107,10 @@ export default class Observable<T = any> {
* @param data data to be sent * @param data data to be sent
*/ */
send(data: T) { send(data: T) {
if (this[ClosedSymbol])
throw new Error("Observable is closed!");
this[LastValueSymbol] = data;
this.subscriber.forEach(e => e(data)); this.subscriber.forEach(e => e(data));
this.events.push(data); this.events.push(data);
if (!this.timeout) { if (!this.timeout) {
@ -69,8 +118,22 @@ export default class Observable<T = any> {
this.subscriberCollect.forEach(cb => { this.subscriberCollect.forEach(cb => {
cb(this.events) cb(this.events)
}); });
this.events = [];
this.timeout = undefined; this.timeout = undefined;
}, this.collect_intervall); }, this.collect_intervall);
} }
} }
/**
* Closes Observable. This will remove all subscribers and mark this observable as closed.
* You won't be able to reopen this observable. All maybe collected data will be discardet.
*/
close() {
this[ClosedSymbol] = true;
this.subscriber = [];
this.subscriberCollect = [];
this.events = [];
if (this.timeout)
clearTimeout(this.timeout)
}
} }