socket.io
socket.io copied to clipboard
socket listen with AbortSignal
Is your feature request related to a problem? Please describe.
When setting up an listener, you end up having to define your callback in a separate variable in order to be able to clear the listener. This makes it so that you lose the convenient typing that the socket.on<Ev>
generic provides.
Describe the solution you'd like
I'd like an AbortSignal
to be able to be passed into the socket.on
function via a third options
argument. The options
can mirror the DOM api's AddEventListenerOptions
:
{
once?: boolean;
signal?: AbortSignal;
}
When the signal fires, the listener would be removed. This will make it much more convenient to cleanup the listeners, and could potentially allow for cleaning up multiple listeners with a single controller call. This also aligns with the trend towards adopting AbortController
s in various APIs (axios ,fetch ,DOM eventListeners, node's timer promises, and likely more).
Describe alternatives you've considered It isn't complicated to set up a wrapper function to accomplish this from a user side. So maybe adding something like this to the documentation could suffice?
JavaScript Variant
/**
* @typedef SocketOnOptions
* @property {AbortSignal} [signal] If an AbortSignal is passed for signal, then the event listener will be removed when signal is aborted.
* @property {boolean} [once] When set to true, once indicates that the callback will only be invoked once after which the event listener will be removed.
*/
/**
* Adds the listener function as an event listener for ev.
*
* This allows for convenience of passing options including a
* {@link SocketOnOptions.signal `signal`} to remove the listener when desired
*
* @template {Parameters<typeof socket.on>[0]} Ev Name of the event
* @param {Ev} ev Name of the event
* @param {Parameters<typeof socket.on<Ev>>[1]} listener Callback function
* @param {SocketOnOptions} [param2]
*/
export function socketOn(
ev,
listener,
{ signal, once } = {}
) {
if (once) {
socket.once(ev, listener);
} else {
socket.on(ev, listener);
}
signal?.addEventListener(
"abort",
() => {
socket.off(ev, listener);
},
{ once: true }
);
}
TypeScript Variant
export interface SocketOnOptions {
/**
* If an AbortSignal is passed for signal, then the event listener will be removed when signal is aborted.
*/
signal?: AbortSignal;
/**
* When set to true, once indicates that the callback will only be invoked once after which the event listener will be removed.
*/
once?: boolean;
}
/**
* Adds the listener function as an event listener for ev.
*
* This allows for convenience of passing options including a
* {@link SocketOnOptions.signal `signal`} to remove the listener when desired
*
* @param ev Name of the event
* @param listener Callback function
* @param options
*/
export function socketOn<Ev extends Parameters<typeof socket.on>[0]>(
ev: Ev,
listener: Parameters<typeof socket.on<Ev>>[1],
{ signal, once }: SocketOnOptions = {}
) {
if (once) {
socket.once(ev, listener);
} else {
socket.on(ev, listener);
}
signal?.addEventListener(
"abort",
() => {
socket.off(ev, listener);
},
{ once: true }
);
}