UNPKG

@downpourdigital/dispatcher

Version:
123 lines (115 loc) 3.88 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); class Subscription { constructor(observer, subscribable) { this.observer = observer; this.subscribable = subscribable; } unsubscribe() { this.subscribable.unsubscribe(this); } } class PassiveSubscription extends Subscription { constructor(observer, subscribable) { super((cb, payload) => { cb(); observer(payload); return null; }, subscribable); } } class Subscribable { constructor() { this.listeners = []; } subscribe(observer) { const subscription = new Subscription(observer, this); this.listeners.push(subscription); return subscription; } subscribePassive(observer) { const subscription = new PassiveSubscription(observer, this); this.listeners.push(subscription); return subscription; } unsubscribe(subscription) { this.listeners.splice(this.listeners.findIndex(s => s === subscription), 1); } } class PersistentEvent { constructor(listeners, payload, mayCancelAfterCallback) { this.canceled = false; this.isAccumulating = true; this.listeners = []; this.completedListeners = []; this.mayCancelAfterCallback = !!mayCancelAfterCallback; this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); listeners.forEach((s) => { const ref = { subscription: s, cancel: null, }; this.listeners.push(ref); const cancel = s.observer(() => { this.completeCallback(s); }, payload) || null; ref.cancel = cancel; }); this.isAccumulating = false; if (this.listeners.length === 0 && this.resolve) this.resolve(); } completeCallback(subscription) { if (!this.canceled) { const [listener] = this.listeners.splice(this.listeners.findIndex(l => l.subscription === subscription), 1); if (this.mayCancelAfterCallback && listener) { this.completedListeners.push(listener); } if (this.listeners.length === 0 && !this.isAccumulating && this.resolve) { this.resolve(); } } } cancel() { if (!this.canceled) { this.canceled = true; this.listeners.forEach((listener) => { if (listener.cancel) listener.cancel(); }); if (this.mayCancelAfterCallback) { this.completedListeners.forEach((listener) => { if (listener.cancel) listener.cancel(); }); } if (this.reject) this.reject(); } } } class EventDispatcher extends Subscribable { constructor(props = {}) { super(); this.events = []; const { mayCancelAfterCallback = true, } = props; this.mayCancelAfterCallback = mayCancelAfterCallback; } dispatchPassive(payload) { this.listeners.forEach(s => s.observer(() => { }, payload)); } dispatch(payload) { const event = new PersistentEvent(this.listeners, payload, this.mayCancelAfterCallback); this.events.push(event); event.promise.catch(() => { }).finally(() => { this.events.splice(this.events.findIndex(e => e === event), 1); }); return event; } cancelAll() { this.events.forEach(e => e.cancel()); } } exports.EventDispatcher = EventDispatcher; exports.Subscribable = Subscribable;