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
text/typescript
// 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
};