@cdellacqua/signals
Version:
A simple signal pattern implementation that enables reactive programming
119 lines (118 loc) • 3.01 kB
JavaScript
function deriveSignal(signal$, transform) {
const base$ = makeSignal();
const emitTransformed = (data) => {
base$.emit(transform(data));
};
const handleUnsubscribe = () => {
if (unsubscribeOriginal && base$.nOfSubscriptions() === 0) {
unsubscribeOriginal();
unsubscribeOriginal = null;
}
};
let unsubscribeOriginal = null;
return {
nOfSubscriptions: base$.nOfSubscriptions,
subscribe: (s) => {
const unsubscribe = base$.subscribe(s);
if (!unsubscribeOriginal) {
unsubscribeOriginal = signal$.subscribe(emitTransformed);
}
return () => {
unsubscribe();
handleUnsubscribe();
};
},
subscribeOnce: (s) => {
const unsubscribe = base$.subscribeOnce((v) => {
s(v);
handleUnsubscribe();
});
if (!unsubscribeOriginal) {
unsubscribeOriginal = signal$.subscribe(emitTransformed);
}
return () => {
unsubscribe();
handleUnsubscribe();
};
}
};
}
function coalesceSignals(signals$) {
const base$ = makeSignal();
const emit = (data) => {
base$.emit(data);
};
const handleUnsubscribe = () => {
if (unsubscribeOriginals && base$.nOfSubscriptions() === 0) {
unsubscribeOriginals.forEach((unsub) => unsub());
unsubscribeOriginals = null;
}
};
let unsubscribeOriginals = null;
return {
nOfSubscriptions: base$.nOfSubscriptions,
subscribe: (s) => {
const unsubscribe = base$.subscribe(s);
if (!unsubscribeOriginals) {
unsubscribeOriginals = signals$.map((signal$) => signal$.subscribe(emit));
}
return () => {
unsubscribe();
handleUnsubscribe();
};
},
subscribeOnce: (s) => {
const unsubscribe = base$.subscribeOnce((v) => {
s(v);
handleUnsubscribe();
});
if (!unsubscribeOriginals) {
unsubscribeOriginals = signals$.map((signal$) => signal$.subscribe(emit));
}
return () => {
unsubscribe();
handleUnsubscribe();
};
}
};
}
function makeSignal() {
const subscribers = [];
function emit(v) {
if (subscribers.length === 0) {
return;
}
for (const subscriber of subscribers.slice()) {
subscriber(v);
}
}
function unsubscribe(subscriber) {
const index = subscribers.indexOf(subscriber);
if (index !== -1) {
subscribers.splice(index, 1);
}
}
function subscribe(subscriber) {
const index = subscribers.indexOf(subscriber);
if (index === -1) {
subscribers.push(subscriber);
}
return () => unsubscribe(subscriber);
}
function subscribeOnce(subscriber) {
const unsubscribeWrapper = subscribe((v) => {
unsubscribeWrapper();
subscriber(v);
});
return unsubscribeWrapper;
}
return {
emit,
subscribe,
subscribeOnce,
nOfSubscriptions() {
return subscribers.length;
}
};
}
export { coalesceSignals, deriveSignal, makeSignal };