UNPKG

@cloudcome/utils-vue

Version:
1 lines 6.19 kB
{"version":3,"file":"async.mjs","sources":["../src/async.ts"],"sourcesContent":["import type { AnyArray } from '@cloudcome/utils-core/types';\nimport { type ComputedRef, type Ref, computed, ref } from 'vue';\n\n/**\n * 异步操作的配置选项\n * @template T 异步操作返回的数据类型\n * @template P 异步操作的参数类型\n */\nexport type UseAsyncOptions<I extends AnyArray, O> = {\n placeholder?: () => O;\n\n /**\n * 异步操作开始前的回调函数。\n * 可用于执行初始化逻辑或显示加载状态。\n */\n onBefore?: (...inputs: I) => unknown;\n\n /**\n * 异步操作成功后的回调函数。\n * @param data 异步操作返回的数据。\n * 可用于处理成功后的数据更新或通知。\n */\n onSuccess?: (data: O, ...inputs: I) => unknown;\n\n /**\n * 异步操作失败后的回调函数。\n * @param err 异步操作抛出的错误。\n * 可用于记录错误日志或显示错误提示。\n */\n onError?: (err: unknown, ...inputs: I) => unknown;\n\n /**\n * 异步操作结束后的回调函数(无论成功或失败)。\n * 可用于清理操作或触发后续逻辑。\n */\n onAfter?: (...inputs: I) => unknown;\n};\n\nexport type UseAsyncState<O> = {\n times: number;\n loading: boolean;\n error: unknown;\n data: O | null;\n};\n\nexport type UseAsyncStateFilled<O> = {\n times: number;\n loading: boolean;\n error: unknown;\n data: O;\n};\n\nexport type UseAsyncOutput<I extends AnyArray, O> = {\n state: ComputedRef<UseAsyncState<O>>;\n loading: Ref<boolean>;\n data: Ref<O | null>;\n error: Ref<unknown>;\n run: (...inputs: I) => void;\n runAsync: (...inputs: I) => Promise<O>;\n};\n\nexport type UseAsyncOutputFilled<I extends AnyArray, O> = {\n state: ComputedRef<UseAsyncStateFilled<O>>;\n loading: Ref<boolean>;\n data: Ref<O>;\n error: Ref<unknown>;\n run: (...inputs: I) => void;\n runAsync: (...inputs: I) => Promise<O>;\n};\n\n/**\n * 用于处理异步操作的组合式函数。\n * 提供加载状态、数据、错误信息以及执行方法。\n * @template O 异步函数返回的数据类型\n * @template I 异步函数的入参类型\n * @param fn 异步函数,接收参数并返回 Promise。\n * @param options 异步操作的配置选项。\n * @returns 包含状态和操作方法的对象:\n * - loading: 是否正在加载。\n * - data: 异步操作返回的数据。\n * - error: 异步操作抛出的错误。\n * - runAsync: 执行异步操作并返回 Promise。\n * - run: 执行异步操作但不返回 Promise。\n * @example\n * const { loading, data, error, runAsync, run } = useAsync(async (id: number) => {\n * const response = await fetch(`/api/user/${id}`);\n * return response.json();\n * }, {\n * onBefore: () => console.log('Fetching user data...'),\n * onSuccess: (data) => console.log('User data fetched:', data),\n * onError: (err) => console.error('Failed to fetch user data:', err),\n * onFinally: () => console.log('Fetch operation completed.'),\n * });\n */\nexport function useAsync<I extends AnyArray, O>(\n fn: (...inputs: I) => Promise<O>,\n options: Omit<UseAsyncOptions<I, O>, 'placeholder'> & { placeholder: () => O },\n): UseAsyncOutputFilled<I, O>;\nexport function useAsync<I extends AnyArray, O>(\n fn: (...inputs: I) => Promise<O>,\n options?: UseAsyncOptions<I, O>,\n): UseAsyncOutput<I, O>;\nexport function useAsync<I extends AnyArray, O>(\n fn: (...inputs: I) => Promise<O>,\n options?: UseAsyncOptions<I, O>,\n): UseAsyncOutput<I, O> {\n const times = ref(0);\n const loading = ref(false);\n const placeholder = options?.placeholder;\n const data = ref(placeholder ? placeholder() : null) as Ref<O | null>;\n const error = ref<unknown>(null);\n const state = computed(() => ({\n times: times.value,\n loading: loading.value,\n data: data.value,\n error: error.value,\n }));\n\n const runAsync = async (...inputs: I): Promise<O> => {\n loading.value = true;\n error.value = null;\n\n try {\n times.value++;\n options?.onBefore?.(...inputs);\n data.value = await fn(...inputs);\n options?.onSuccess?.(data.value, ...inputs);\n return data.value;\n } catch (err) {\n error.value = err;\n options?.onError?.(err, ...inputs);\n throw err;\n } finally {\n loading.value = false;\n options?.onAfter?.(...inputs);\n }\n };\n\n const run = (...inputs: I) => {\n runAsync(...inputs).then();\n };\n\n return {\n state,\n /**\n * 是否正在加载。\n */\n loading,\n\n /**\n * 异步操作返回的数据。\n */\n data,\n\n /**\n * 异步操作抛出的错误。\n */\n error,\n\n /**\n * 执行异步操作并返回 Promise。\n * @param inputs 异步函数的参数。\n * @returns 异步操作的结果。\n */\n runAsync,\n\n /**\n * 执行异步操作但不返回 Promise。\n * @param inputs 异步函数的参数。\n */\n run,\n };\n}\n\n// const { run: run1 } = useAsync(() => Promise.resolve(1));\n// run1();\n\n// const { run: run2 } = useAsync((a: number) => Promise.resolve(1));\n// run2(2);\n\n// const { run: run3 } = useAsync((a: number, b: string) => Promise.resolve(1));\n// run3(2, '2');\n"],"names":[],"mappings":";AAsGgB,SAAA,SACd,IACA,SACsB;AAChB,QAAA,QAAQ,IAAI,CAAC;AACb,QAAA,UAAU,IAAI,KAAK;AACzB,QAAM,cAAc,SAAS;AAC7B,QAAM,OAAO,IAAI,cAAc,YAAA,IAAgB,IAAI;AAC7C,QAAA,QAAQ,IAAa,IAAI;AACzB,QAAA,QAAQ,SAAS,OAAO;AAAA,IAC5B,OAAO,MAAM;AAAA,IACb,SAAS,QAAQ;AAAA,IACjB,MAAM,KAAK;AAAA,IACX,OAAO,MAAM;AAAA,EAAA,EACb;AAEI,QAAA,WAAW,UAAU,WAA0B;AACnD,YAAQ,QAAQ;AAChB,UAAM,QAAQ;AAEV,QAAA;AACI,YAAA;AACG,eAAA,WAAW,GAAG,MAAM;AAC7B,WAAK,QAAQ,MAAM,GAAG,GAAG,MAAM;AAC/B,eAAS,YAAY,KAAK,OAAO,GAAG,MAAM;AAC1C,aAAO,KAAK;AAAA,aACL,KAAK;AACZ,YAAM,QAAQ;AACL,eAAA,UAAU,KAAK,GAAG,MAAM;AAC3B,YAAA;AAAA,IAAA,UACN;AACA,cAAQ,QAAQ;AACP,eAAA,UAAU,GAAG,MAAM;AAAA,IAAA;AAAA,EAEhC;AAEM,QAAA,MAAM,IAAI,WAAc;AACnB,aAAA,GAAG,MAAM,EAAE,KAAK;AAAA,EAC3B;AAEO,SAAA;AAAA,IACL;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA;AAAA,EACF;AACF;"}