First Commit
This commit is contained in:
9
src/index.ts
Normal file
9
src/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import Lock, { Release } from "./lock";
|
||||
import Observable, { ObserverCallback } from "./observable";
|
||||
|
||||
export {
|
||||
Lock,
|
||||
Release,
|
||||
Observable,
|
||||
ObserverCallback
|
||||
}
|
53
src/lock.ts
Executable file
53
src/lock.ts
Executable file
@ -0,0 +1,53 @@
|
||||
export type Release = { release: () => void };
|
||||
|
||||
/**
|
||||
* Basic Locking mechanism for JavaScript
|
||||
*
|
||||
*/
|
||||
export default class Lock {
|
||||
private _locked: boolean = false;
|
||||
|
||||
/**
|
||||
* Returns the state of the Locken
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get locked(): boolean {
|
||||
return this._locked;
|
||||
}
|
||||
private toCome: (() => void)[] = [];
|
||||
|
||||
constructor() {
|
||||
this.release = this.release.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits till lock is free and returns a release function
|
||||
*
|
||||
* @return {function}
|
||||
*/
|
||||
async getLock(): Promise<Release> {
|
||||
if (!this._locked) return { release: this.lock() };
|
||||
else {
|
||||
return new Promise<Release>((resolve) => {
|
||||
this.toCome.push(() => {
|
||||
resolve({ release: this.lock() });
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private lock() {
|
||||
this._locked = true;
|
||||
return this.release;
|
||||
}
|
||||
|
||||
private async release() {
|
||||
let next = this.toCome.shift();
|
||||
if (next) {
|
||||
next();
|
||||
} else {
|
||||
this._locked = false;
|
||||
}
|
||||
}
|
||||
}
|
63
src/observable.ts
Executable file
63
src/observable.ts
Executable file
@ -0,0 +1,63 @@
|
||||
export type ObserverCallback<T> = (data: T[]) => void;
|
||||
|
||||
export default class Observable<T = any> {
|
||||
private subscriber: { callback: ObserverCallback<T>, one: boolean }[] = [];
|
||||
private events: T[] = [];
|
||||
private timeout: number | undefined = undefined;
|
||||
|
||||
constructor(private collect: boolean = true, private collect_intervall: number = 100) { }
|
||||
|
||||
/**
|
||||
* Creates Public API with subscribe and unsubscribe
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
getPublicApi() {
|
||||
return {
|
||||
/**
|
||||
* Subscribe to Observable
|
||||
* @param {function} callback
|
||||
*/
|
||||
subscribe: (callback: ObserverCallback<T>, one: boolean = false) => {
|
||||
let oldcb = this.subscriber.find(e => e.callback === callback);
|
||||
if (oldcb)
|
||||
oldcb.one = one
|
||||
else
|
||||
this.subscriber.push({ callback, one })
|
||||
},
|
||||
/**
|
||||
* Subscribe fron Observable
|
||||
* @param {function} callback
|
||||
*/
|
||||
unsubscribe: (callback: ObserverCallback<T>) => {
|
||||
let idx = this.subscriber.findIndex(e => e.callback === callback);
|
||||
if (idx >= 0) {
|
||||
this.subscriber.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends data to all subscribers
|
||||
* @param data data to be sent
|
||||
*/
|
||||
send(data: T) {
|
||||
if (!this.collect)
|
||||
this.subscriber.forEach(e => e.callback([data]));
|
||||
else {
|
||||
this.events.push(data);
|
||||
if (!this.timeout) {
|
||||
this.timeout = setTimeout(() => {
|
||||
this.subscriber.forEach(cb => {
|
||||
if (cb.one)
|
||||
this.events.forEach(e => cb.callback([e]));
|
||||
else
|
||||
cb.callback(this.events)
|
||||
});
|
||||
this.timeout = undefined;
|
||||
}, this.collect_intervall);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user