UNPKG

@naturalcycles/js-lib

Version:

Standard library for universal (browser + Node.js) javascript

65 lines (64 loc) 2.25 kB
import { _errorDataAppend, TimeoutError } from '../error/error.util.js'; import { _typeCast } from '../types.js'; /** * Decorates a Function with a timeout. * Returns a decorated Function. * * Throws an Error if the Function is not resolved in a certain time. * If the Function rejects - passes this rejection further. */ export function pTimeoutFn(fn, opt) { opt.name ||= fn.name; if (!opt.timeout) { return fn; } return async function pTimeoutInternalFn(...args) { return await pTimeout(() => fn.apply(this, args), opt); }; } /** * Decorates a Function with a timeout and immediately calls it. * * Throws an Error if the Function is not resolved in a certain time. * If the Function rejects - passes this rejection further. */ export async function pTimeout(fn, opt) { if (!opt.timeout) { // short-circuit to direct execution if 0 timeout is passed return await fn(); } const { timeout, name = fn.name || 'pTimeout function', onTimeout } = opt; const fakeError = opt.fakeError || new Error('TimeoutError'); // biome-ignore lint/suspicious/noAsyncPromiseExecutor: ok return await new Promise(async (resolve, reject) => { // Prepare the timeout timer const timer = setTimeout(() => { const err = new TimeoutError(`"${name}" timed out after ${timeout} ms`, opt.errorData); // keep original stack err.stack = fakeError.stack.replace('Error: TimeoutError', 'TimeoutError: ' + err.message); if (onTimeout) { try { resolve(onTimeout(err)); } catch (err) { _typeCast(err); // keep original stack err.stack = fakeError.stack.replace('Error: TimeoutError', err.name + ': ' + err.message); reject(_errorDataAppend(err, opt.errorData)); } return; } reject(err); }, timeout); // Execute the Function try { resolve(await fn()); } catch (err) { reject(err); } finally { clearTimeout(timer); } }); }