UNPKG

parallel-universe

Version:

The set of async flow control structures and promise utils.

88 lines (84 loc) 2.59 kB
'use strict'; var AbortablePromise = require('./AbortablePromise.js'); /** * Publish–subscribe pattern implementation that guarantees the delivery of published messages even if any of listeners * would throw an error. * * @template T The published message. */ class PubSub { constructor() { this._listeners = []; } /** * The number of subscribed listeners. */ get listenerCount() { return this._listeners.length; } /** * Synchronously invokes listeners with the published message. * * @param message The published message. */ publish(message) { for (const listener of this._listeners.slice(0)) { try { listener(message); } catch (error) { setTimeout(() => { // Force uncaught exception throw error; }, 0); } } } /** * Waits for a message that satisfies the given predicate to be published and resolves with that message. * * @param predicate A function that takes the message as a parameter and returns true if the message satisfies the condition, otherwise false. * @returns An {@link AbortablePromise} that resolves with the published message that satisfies the predicate. */ waitFor(predicate) { return new AbortablePromise.AbortablePromise((resolve, _reject, signal) => { const unsubscribe = this.subscribe(message => { if (predicate(message)) { resolve(message); unsubscribe(); } }); signal.addEventListener('abort', unsubscribe); }); } /** * Adds a listener that would receive all messages published via {@link publish}. * * @param listener The callback. * @returns The callback that unsubscribes the listener. */ subscribe(listener) { if (this._listeners.indexOf(listener) === -1) { this._listeners.push(listener); } return () => this.unsubscribe(listener); } /** * Unsubscribes a listener. * * @param listener The callback that was previously {@link subscribe subscribed}. */ unsubscribe(listener) { const index = this._listeners.indexOf(listener); if (index !== -1) { this._listeners.splice(index, 1); } } /** * Unsubscribes all listeners. */ unsubscribeAll() { this._listeners = []; } } exports.PubSub = PubSub;