/** * 清除全局 scope 注册表(用于测试) */ declare const clearPendingRegistry: () => void; /** * Scope 冲突错误 */ declare class PendingScopeConflictError extends Error { readonly scope: string; constructor(scope: string); } /** * pendingFn 回调函数接收的参数 */ type PendingFnParams = { /** 解析后的 scope key */ scope: string; /** 获取当前等待中的 caller 数量(实时值) */ getPendingCount: () => number; }; /** * pendingFn 的回调函数类型 */ type PendingCallbackFn = (params: PendingFnParams, ...args: Args) => T; /** * 感知 pending 状态的 inflight 去重 * * fn 的第一个参数为 PendingFnParams,包含 scope 和 getPendingCount, * 允许根据 pending 状态做自定义处理(如短路检查、日志等)。 * 返回的函数剥掉 PendingFnParams,只暴露业务参数。 * * @param scope 静态 scope 字符串,或基于参数动态生成 scope 的函数 * @param fn 接收 PendingFnParams 的回调函数 * @returns 只保留业务参数的包装函数 * * @example * ```ts * const mountScript = pendingFn( * (url: string) => `script:${url}`, * ({ scope, getPendingCount }, url: string) => { * // 短路:已挂载 * const existing = document.getElementById(scope); * if (existing) return { element: existing }; * * // 实际挂载,执行期间 getPendingCount() 可获取等待数 * return loadScript(url); * }, * ); * * // 并发调用,只执行一次挂载 * await Promise.all([mountScript('/lib.js'), mountScript('/lib.js')]); * ``` */ declare const pendingFn: (scope: string | ((...args: Args) => string), fn: PendingCallbackFn) => ((...args: Args) => Promise>); /** * 基于 scope 的 inflight 去重 * * 同一 scope 下并发调用只执行一次 fn,所有 callers 共享同一个 Promise 结果。 * 执行完毕后 scope 释放,下一次调用开启新的执行周期。 * * @param scope 静态 scope 字符串,或基于参数动态生成 scope 的函数 * @param fn 要包装的函数(同步或异步) * @returns 包装后的去重函数 * * @example 静态 scope * ```ts * const fetchConfig = pending('config', () => fetch('/api/config').then(r => r.json())); * * // 并发调用 3 次,只执行 1 次 fetch * const [a, b, c] = await Promise.all([fetchConfig(), fetchConfig(), fetchConfig()]); * // a === b === c * ``` * * @example 动态 scope * ```ts * const fetchUser = pending( * (id: string) => `user:${id}`, * (id: string) => fetch(`/api/user/${id}`).then(r => r.json()), * ); * * // 相同 id 去重,不同 id 独立执行 * await Promise.all([fetchUser('1'), fetchUser('1'), fetchUser('2')]); * // fetchUser('1') 只执行一次,fetchUser('2') 独立执行一次 * ``` */ declare const pending: (scope: string | ((...args: Parameters) => string), fn: F) => ((...args: Parameters) => Promise>>); /** * 异步工具模块 */ type AnyFn = (...args: any[]) => any; /** * 重试回调参数 */ type RetryFnParams = { /** 当前尝试次数(从 1 开始) */ attempt: number; /** 触发重试的错误(首次执行时为 undefined) */ error: unknown; /** 只读的重试选项 */ readonly options: RetryOptions; }; /** * 重试选项 */ type RetryOptions = { /** 最大尝试次数,默认 3 */ attempts?: number; /** 重试间隔(毫秒),支持固定值或基于 RetryFnParams 的动态计算 */ delay?: number | ((params: RetryFnParams) => number); /** 重试前的回调,可用于日志记录 */ onRetry?: (params: RetryFnParams) => void; }; /** * retryFn 的回调函数类型 */ type RetryCallbackFn = (params: RetryFnParams, ...args: Args) => T; /** * 重试耗尽错误 * * 当异步操作在达到最大重试次数后仍然失败时抛出 */ declare class RetryExhaustedError extends Error { readonly attempt: number; readonly error: unknown; readonly options: RetryOptions; constructor(params: RetryFnParams); } /** * 超时错误 * * 当异步操作超过指定时间仍未完成时抛出 */ declare class TimeoutError extends Error { readonly ms: number; /** * @param ms 超时毫秒数 */ constructor(ms: number); } /** * 透明包装异步/同步函数,返回自动重试的版本 * * 返回的函数保持原函数的参数签名,返回值统一为 Promise * * @param fn 要包装的函数(同步或异步) * @param options 重试选项 * @returns 包装后的函数 * * @example * ```ts * const fetchUserWithRetry = retry( * (id: string) => fetch(`/api/user/${id}`).then(r => r.json()), * { attempts: 3, delay: 1000 }, * ); * * const user = await fetchUserWithRetry('123'); * ``` * * @example 指数退避 * ```ts * const fetchWithBackoff = retry(fetchData, { * attempts: 5, * delay: ({ attempt }) => Math.min(1000 * 2 ** (attempt - 1), 30000), * }); * ``` */ declare const retry: (fn: F, options?: RetryOptions) => ((...args: Parameters) => Promise>>); /** * 创建感知重试状态的函数 * * fn 的第一个参数为 RetryFnParams,包含 attempt 和 options, * 允许根据重试次数做差异化处理。返回的函数剥掉 RetryFnParams, * 只暴露业务参数。 * * @param fn 接收 RetryFnParams 的回调函数 * @param options 重试选项 * @returns 只保留业务参数的包装函数 * * @example * ```ts * const fetchWithFallback = retryFn( * ({ attempt }, id: string) => { * const url = attempt === 1 ? '/api/primary' : '/api/fallback'; * return fetch(`${url}/${id}`).then(r => r.json()); * }, * { attempts: 3 }, * ); * * const data = await fetchWithFallback('123'); * ``` */ declare const retryFn: (fn: RetryCallbackFn, options?: RetryOptions) => ((...args: Args) => Promise>); /** * 包装函数,添加超时控制 * * 返回的函数保持原函数的参数签名,返回值统一为 Promise。 * 如果执行超过指定时间,将抛出 TimeoutError。 * * @param fn 要包装的函数(同步或异步) * @param ms 超时毫秒数 * @returns 包装后的函数 * * @example * ```ts * const fetchWithTimeout = timeout( * (url: string) => fetch(url).then(r => r.json()), * 5000, * ); * * const data = await fetchWithTimeout('/api/data'); * ``` */ declare const timeout: (fn: F, ms: number) => ((...args: Parameters) => Promise>>); /** * 延迟指定毫秒数,可选延迟后执行函数 * * @param ms 延迟毫秒数 * @param fn 延迟后执行的函数(可选) * @returns 无 fn 时返回 Promise,有 fn 时返回 Promise>> * * @example * ```ts * // 纯等待 * await sleep(1000); * * // 延迟后执行 * const data = await sleep(1000, () => fetchData()); * ``` */ declare function sleep(ms: number): Promise; declare function sleep(ms: number, fn: F): Promise>>; export { PendingScopeConflictError, RetryExhaustedError, TimeoutError, clearPendingRegistry, pending, pendingFn, retry, retryFn, sleep, timeout }; export type { AnyFn, PendingCallbackFn, PendingFnParams, RetryCallbackFn, RetryFnParams, RetryOptions };