UNPKG

uniapp-use-request

Version:

一个功能强大且高度可配置的 Vue 3 Composition API 请求 Hook,灵感来源于 [ahooks](https://ahooks.js.org/hooks/request/use-request) 和 [SWR](https://swr.vercel.app/)。它内置了缓存、防抖、节流、轮询、重试、请求队列和并发控制等特性。

231 lines (198 loc) 6.59 kB
// hooks/useRequest/index.ts import { watch, unref } from 'vue'; import { RequestOptions, RequestResult } from './types'; import { useRequestCore } from './core'; import { generateCacheKey, getCache, setCache, clearCache as clearCacheByKey } from './cache'; import { createDebouncedRequest, createThrottledRequest } from './debounceThrottle'; import { enqueueRequest, cancelQueuedRequest } from './queue'; import { applyInitHooks, applyRequestHooks, applySuccessHooks, applyErrorHooks, applyFinallyHooks } from './plugin'; import { setConfig, setBaseURL, getConfig, getBaseURL, addInterceptor, removeInterceptor, clearInterceptors, applyRequestInterceptors, applyResponseInterceptors, applyErrorInterceptors, resolveURL, createRequestInterceptor, createResponseInterceptor, createErrorInterceptor } from './config'; /** * 请求Hook * @param url 请求地址或请求函数 * @param options 请求配置 * @returns 请求结果 */ export function useRequest<T = any>( url: string | ((params?: any) => string), options: RequestOptions = {} ): RequestResult<T> { // 规范化参数:如果 params 未定义,则使用 data if (options.params === undefined && options.data !== undefined) { options.params = options.data; } // 应用初始化钩子,合并全局配置 const initialOptions = applyInitHooks({ ...getConfig(), ...options }); // 创建核心请求实例 const requestInstance = useRequestCore<T>(url, initialOptions); // 包装原始run方法 const originalRun = requestInstance.run; // 重写run方法,添加缓存、防抖、节流、队列等功能 requestInstance.run = async (params?: any): Promise<T> => { const mergedOptions = { ...initialOptions, params: { ...initialOptions.params, ...params } }; // 获取请求URL,并应用baseURL let requestUrl: string; if (typeof url === 'function') { requestUrl = url(mergedOptions.params); } else { // 解析URL,添加baseURL requestUrl = resolveURL(url); } // 生成缓存键 const cacheKey = generateCacheKey(requestUrl, mergedOptions.params); // 检查缓存 if (mergedOptions.cacheTime && mergedOptions.cacheTime > 0) { const cachedData = getCache<T>(cacheKey, mergedOptions.cacheTime); if (cachedData !== undefined) { requestInstance.data.value = cachedData; return cachedData; } } // 创建请求执行函数 const executeRequest = async (): Promise<T> => { try { // 应用请求拦截器 const interceptedOptions = await applyRequestInterceptors(mergedOptions); // 应用请求前钩子 const processedOptions = await applyRequestHooks(interceptedOptions); // 执行原始请求,传递完整的配置对象 const result = await originalRun(processedOptions); // 将响应拦截器的调用单独包裹起来,以捕获其中抛出的错误 try { // 应用响应拦截器 const interceptedResult = await applyResponseInterceptors(result, processedOptions); // 应用请求成功钩子 const processedResult = await applySuccessHooks(interceptedResult, processedOptions); // 设置缓存 if (processedOptions.cacheTime && processedOptions.cacheTime > 0) { setCache(cacheKey, processedResult, processedOptions.params, processedOptions.cacheTime); } // 在这里将最终处理过的数据赋值给 ref requestInstance.data.value = processedResult; return processedResult; } catch (error: any) { // 如果响应拦截器抛出错误,则将其作为请求错误处理 throw error; } } catch (error: any) { // 尝试加载陈旧缓存 const staleData = getCache<T>(cacheKey, mergedOptions.cacheTime || 0, true); if (staleData !== undefined) { requestInstance.data.value = staleData; } // 应用错误拦截器 const interceptedError = await applyErrorInterceptors(error, mergedOptions); // 如果错误已被拦截器处理,返回一个默认值 if (interceptedError === undefined) { return {} as T; } // 应用错误钩子 const processedError = await applyErrorHooks(interceptedError, mergedOptions); // 如果错误已被处理,返回一个默认值 if (processedError === undefined) { return {} as T; } throw processedError; } finally { // 应用完成钩子 await applyFinallyHooks(mergedOptions); } }; // 处理防抖 if (mergedOptions.debounce && mergedOptions.debounceTime && mergedOptions.debounceTime > 0) { const debouncedRequest = createDebouncedRequest(executeRequest, mergedOptions.debounceTime); return debouncedRequest(); } // 处理节流 if (mergedOptions.throttle && mergedOptions.throttleTime && mergedOptions.throttleTime > 0) { const throttledRequest = createThrottledRequest(executeRequest, mergedOptions.throttleTime); return throttledRequest(); } // 处理请求队列 if (mergedOptions.requestId) { return enqueueRequest( mergedOptions.requestId, mergedOptions.priority || 0, executeRequest ); } // 直接执行请求 return executeRequest(); }; // 重写clearCache方法 requestInstance.clearCache = () => { const requestUrl = typeof url === 'function' ? url(initialOptions.params) : resolveURL(url); const cacheKey = generateCacheKey(requestUrl, initialOptions.params); clearCacheByKey(cacheKey); }; // 重写cancel方法 const originalCancel = requestInstance.cancel; requestInstance.cancel = () => { if (initialOptions.requestId) { cancelQueuedRequest(initialOptions.requestId); } originalCancel(); }; // 监听ready变化 if (initialOptions.ready !== undefined) { watch( () => unref(initialOptions.ready), (isReady) => { if (isReady && !requestInstance.loading.value) { requestInstance.run(); } }, { immediate: true } ); } // 自动执行 if (!initialOptions.manual && initialOptions.ready === undefined) { requestInstance.run(); } return requestInstance; } // 导出所有模块 export * from './core'; export * from './cache'; export * from './debounceThrottle'; export * from './queue'; export * from './plugin'; export * from './config'; // 导出类型 export type { RequestOptions, RequestResult, RequestTask, CacheData, RequestPlugin } from './types'; export type { Interceptor } from './config'; // 导出配置相关函数 export { setConfig, setBaseURL, getConfig, getBaseURL, addInterceptor, removeInterceptor, clearInterceptors, resolveURL, createRequestInterceptor, createResponseInterceptor, createErrorInterceptor };