71 lines
2.4 KiB
JavaScript
71 lines
2.4 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = void 0;
|
||
|
var _errors = require("./errors");
|
||
|
// Like an EventEmitter, but for only a single "event". This provides type-safety
|
||
|
// for the values emitted. Rather than passing predetermined strings (which can
|
||
|
// be misspelled), create an instance of ValueEmitter for every logical "event"
|
||
|
// to be dispatched, and type it according to the type of value emitted.
|
||
|
class ValueEmitter {
|
||
|
// An array of listeners. One might think a Set would be better for O(1) removal,
|
||
|
// but splicing a JS array gets pretty close, and copying the array (as is done
|
||
|
// in emit) is far faster than a Set copy: https://github.com/atom/event-kit/pull/39
|
||
|
_listeners = [];
|
||
|
_disposed = false;
|
||
|
addListener(listener) {
|
||
|
if (this._disposed) {
|
||
|
throw new _errors.AlreadyDisposedError('Cannot add a listener since this ValueEmitter has been disposed');
|
||
|
}
|
||
|
this._listeners.push(listener);
|
||
|
|
||
|
// Close over a reference to this emitter in the disposable below, rather
|
||
|
// than referencing `this` directly. This allows us to set it to null after
|
||
|
// slicing out the listener.
|
||
|
// This prevents anyone holding onto the disposable after disposal from
|
||
|
// unintentionally retaining a reference to this emitter.
|
||
|
let emitter = this;
|
||
|
return {
|
||
|
dispose() {
|
||
|
if (emitter == null) {
|
||
|
return;
|
||
|
}
|
||
|
if (emitter._disposed) {
|
||
|
emitter = null;
|
||
|
return;
|
||
|
}
|
||
|
let listeners = emitter._listeners;
|
||
|
let listenerIndex = listeners.indexOf(listener);
|
||
|
if (listenerIndex > -1) {
|
||
|
listeners.splice(listenerIndex, 1);
|
||
|
}
|
||
|
emitter = null;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
emit(value) {
|
||
|
if (this._disposed) {
|
||
|
throw new _errors.AlreadyDisposedError('Cannot emit since this ValueEmitter has been disposed');
|
||
|
}
|
||
|
|
||
|
// Iterate over a copy of listeners. This prevents the following cases:
|
||
|
// * When a listener callback can itself register a new listener and be
|
||
|
// emitted as part of this iteration.
|
||
|
// * When a listener callback disposes of this emitter mid-emit, preventing
|
||
|
// other listeners from receiving the event.
|
||
|
let listeners = this._listeners.slice();
|
||
|
for (let i = 0; i < listeners.length; i++) {
|
||
|
listeners[i](value);
|
||
|
}
|
||
|
}
|
||
|
dispose() {
|
||
|
if (this._disposed) {
|
||
|
return;
|
||
|
}
|
||
|
this._listeners = [];
|
||
|
this._disposed = true;
|
||
|
}
|
||
|
}
|
||
|
exports.default = ValueEmitter;
|