Skip to content

Commit

Permalink
once
Browse files Browse the repository at this point in the history
  • Loading branch information
samthor committed Sep 2, 2024
1 parent f005580 commit 5118935
Showing 1 changed file with 33 additions and 12 deletions.
45 changes: 33 additions & 12 deletions src/notifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type NotifierListener<T> = {
/**
* Adds a listener to this notifier. Allows duplicates.
*/
addListener(fn: (value: T) => void, args?: { signal?: AbortSignal }): void;
addListener(fn: (value: T) => void, args?: { signal?: AbortSignal; once?: boolean }): void;
};

export type BuildNotifierArgs = {
Expand Down Expand Up @@ -50,29 +50,50 @@ export function buildNotifier<T>(args?: Partial<BuildNotifierArgs>): Notifier<T>
return;
}

let removed = false;
const remove = () => {
if (removed) {
return;
}
removed = true;

const index = listeners.indexOf(fn);
if (index === -1) {
return;
}
listeners.splice(index, 1);
if (listeners.length === 0) {
// throw is fine, nothing else to do
teardown?.();
}
};
const once = Boolean(args?.once);

// we explicitly allow duplicates, create a fake
const exists = listeners.includes(fn);
if (exists) {
const realFn = fn;
fn = (value) => realFn(value);
}

if (once) {
const realFn = fn;
fn = (value) => {
try {
realFn(value);
} finally {
remove();
}
};
}

// try/finally in case setup() throws
try {
if (listeners.length === 0) {
setup?.();
}
} finally {
signal?.addEventListener('abort', () => {
const index = listeners.indexOf(fn);
if (index === -1) {
return;
}
listeners.splice(index, 1);
if (listeners.length === 0) {
// throw is fine, nothing else to do
teardown?.();
}
});
signal?.addEventListener('abort', remove);
listeners.push(fn);
}
},
Expand Down

0 comments on commit 5118935

Please sign in to comment.