/** * 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) { let onTimeHandler: (arg: T) => any = (arg) => {} let lateHandler: (arg: T) => any = (arg) => {} let timeoutHandler: () => any = () => {} 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 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 }