/** * Base interface representing a timeout subscriber. */ export interface TimeoutSubscriber { /** * Handler will execute if the promise resolves before the timeout occurs. * @param handler */ onTime: (handler: (arg: T) => any) => TimeoutSubscriber, /** * Handler will execute if the promise resolves after the timeout occurs. * @param handler */ late: (handler: (arg: T) => any) => TimeoutSubscriber, /** * Handler will execute if the promise has not resolved when the timeout occurs. * @param handler */ timeout: (handler: () => any) => TimeoutSubscriber, /** * Start the timer. */ run: () => Promise, } /** * Subscribe to a promise with a timeout. * @param {number} timeout - timeout in milliseconds * @param {Promise} promise - the promise to subscribe to */ export function withTimeout(timeout: number, promise: Promise): TimeoutSubscriber { let onTimeHandler: (arg: T) => any = () => {} // eslint-disable-line @typescript-eslint/no-empty-function let lateHandler: (arg: T) => any = () => {} // eslint-disable-line @typescript-eslint/no-empty-function let timeoutHandler: () => any = () => {} // eslint-disable-line @typescript-eslint/no-empty-function const sub = { onTime: handler => { onTimeHandler = handler return sub }, late: handler => { lateHandler = handler return sub }, timeout: handler => { timeoutHandler = handler return sub }, run: async () => { let expired = false let resolved = false if ( timeout ) { setTimeout(() => { expired = true if ( !resolved ) { timeoutHandler() } }, timeout) } const result: T = await promise resolved = true if ( !expired ) { await onTimeHandler(result) } else { await lateHandler(result) } return result }, } as TimeoutSubscriber return sub }