diff --git a/package.json b/package.json index 0e8d8cb..e9105ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hibas123/utils", - "version": "2.1.1", + "version": "2.2.0", "description": "Different Utilities, that are not worth own packages", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/readme.md b/readme.md index 3ca44ad..a6865a8 100644 --- a/readme.md +++ b/readme.md @@ -35,8 +35,8 @@ Usage: const server = new Observable(); // Get new Observable Server - // Server can only send, not subscribe to messages - // Receiving is only possible via the public API + // Server can send and subscribe to messages + // The publicAPI will only make the receiving parts available const public = server.getPublicApi(); const func = (data)=>{ @@ -44,10 +44,15 @@ Usage: } // func will be callen when a message is available - public.subscribe(func); + let unsubscribe = public.subscribe(func); server.send("Hello World"); + // Unsubscribe using the returned function from subscribe + unsubscribe(); + + // OR + // This will unsubscribe the function. Please note, that it can // only unsubscribe the exact function, that is used in subscribe public.unsubscribe(func); @@ -56,6 +61,44 @@ Usage: server.send("Hello World2"); ``` +## AwaitStore + +This component can be used to await a specific value or to act as an variable with events. + +Usage: +``` typescript + import { AwaitStore } from "@hibas123/util"; + + const server = new AwaitStore(0); // Set initial value + + // Server can send and subscribe to messages + // Only receiving is possible using the public API + const public = server.getPublicApi(); + + const func = (data)=>{ + console.log(data); + } + + // awaitValue will also return a .ignore() function, that can be used to abort the promise completely + public.awaitValue(5).then(()=>console.log("Got 5")); + + // func will be callen when a message is available and once with the current value + // This will call func with the current value (0) and on every change after. + public.subscribe(func); + + // This send will trigger the subscribtion func and also release the awaitValue causing "Got 5" + // to appear in the console + server.send(5); + + // This will unsubscribe the function. Please note, that it can + // only unsubscribe the exact function, that is used in subscribe + public.unsubscribe(func); + + // This now won't call func anymore + server.send(8); +``` + + ## License MIT diff --git a/src/awaiter.ts b/src/awaiter.ts new file mode 100644 index 0000000..5fea96e --- /dev/null +++ b/src/awaiter.ts @@ -0,0 +1,78 @@ +import Observable, { ObserverCallback } from "./observable"; + +export default class AwaitStore { + private observable = new Observable(); + constructor(private _value: T) { + this.subscribe = this.subscribe.bind(this); + this.unsubscribe = this.unsubscribe.bind(this); + } + + get value() { + return this._value; + } + + send(value: T) { + this._value = value; + this.observable.send(value); + } + + subscribe(handler: ObserverCallback) { + handler(this._value); + this.observable.subscribe(handler); + return () => this.unsubscribe(handler); + } + + unsubscribe(handler: ObserverCallback) { + this.observable.unsubscribe(handler); + } + + awaitValue(val: T): PromiseLike & { catch: (cb: (err: any) => PromiseLike) => PromiseLike, ignore: () => void } { + + let ignore: () => void; + + let prms = new Promise(yes => { + const cb = () => { + if (this._value === val) { + yes(); + this.observable.unsubscribe(cb); + return true; + } + + return false + } + + ignore = () => { + this.observable.unsubscribe(cb); + } + + if (!cb()) { + this.observable.subscribe(cb); + } + }); + + return { + then: prms.then.bind(prms), + catch: prms.catch.bind(prms), + ignore: () => ignore() + } + } + + /** + * Creates Public API with subscribe and unsubscribe + * + * @returns {object} + */ + getPublicApi() { + if (this.observable.closed) + throw new Error("Observable is closed!"); + return { + subscribe: (callback: ObserverCallback) => this.subscribe(callback), + unsubscribe: (callback: ObserverCallback) => this.unsubscribe(callback), + awaitValue: (value: T) => this.awaitValue(value) + } + } + + close() { + this.observable.close(); + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 03d06a2..dd390cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import Lock, { Release } from "./lock"; import Observable, { ObserverCallback, ObserverCallbackCollect, ObservableInterface } from "./observable"; +import AwaitStore from "./awaiter"; export { Lock, @@ -7,5 +8,6 @@ export { Observable, ObserverCallback, ObserverCallbackCollect, - ObservableInterface + ObservableInterface, + AwaitStore } \ No newline at end of file diff --git a/src/observable.ts b/src/observable.ts index 5f144eb..5770394 100755 --- a/src/observable.ts +++ b/src/observable.ts @@ -43,6 +43,8 @@ export default class Observable { let oldcb = this.subscriber.find(e => e === callback); if (!oldcb) this.subscriber.push(callback) + + return () => this.unsubscribe(callback); } unsubscribe(callback: ObserverCallback | ObserverCallbackCollect) {