Merge pull request #282 from qqlcx5/base-useRequest

修复了取消请求时未捕获的 Promise 错误,并确保了 run 函数的返回类型正确。
This commit is contained in:
菲鸽
2025-09-23 18:04:21 +08:00
committed by GitHub
3 changed files with 48 additions and 12 deletions

View File

@@ -21,8 +21,8 @@ export interface IFooItem {
}
/** GET 请求 */
export function getFooAPI(name: string) {
return http.get<IFooItem>('/foo', { name })
export async function getFooAPI(name: string) {
return await http.get<IFooItem>('/foo', { name })
}
/** GET 请求;支持 传递 header 的范例 */
export function getFooAPI2(name: string) {

View File

@@ -26,27 +26,62 @@ interface IUseRequestReturn<T, P = undefined> {
* @returns 返回一个对象{loading, error, data, run},包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。
*/
export default function useRequest<T, P = undefined>(
func: (args?: P) => HttpRequestResult<T>,
func: (args?: P) => Promise<T> | Promise<HttpRequestResult<T>> | HttpRequestResult<T> | T,
options: IUseRequestOptions<T> = { immediate: false },
): IUseRequestReturn<T, P> {
const loading = ref(false)
const error = ref<boolean | Error>(false)
const data = ref<T | undefined>(options.initialData) as Ref<T | undefined>
let requestTask: UniApp.RequestTask | undefined
const isCancelled = ref(false)
const run = async (args?: P) => {
const run = async (args?: P): Promise<T | undefined> => {
loading.value = true
const { promise, requestTask: task } = func(args)
requestTask = task // Store the requestTask
error.value = false
isCancelled.value = false
let promise: Promise<T | undefined>
const result = func(args)
if (result instanceof Promise) {
promise = result.then((res) => {
if (res && typeof (res as HttpRequestResult<T>).promise === 'object' && typeof (res as HttpRequestResult<T>).requestTask === 'object') {
const { promise: p, requestTask: task } = res as HttpRequestResult<T>
requestTask = task
if (isCancelled.value) {
task.abort()
throw new Error('Request cancelled')
}
return p
}
if (isCancelled.value) {
throw new Error('Request cancelled')
}
return res as T | undefined
}) as Promise<T | undefined>
}
else if (result && typeof (result as HttpRequestResult<T>).promise === 'object' && typeof (result as HttpRequestResult<T>).requestTask === 'object') {
const { promise: p, requestTask: task } = result as HttpRequestResult<T>
requestTask = task
promise = p
}
else {
promise = Promise.resolve(result as T | undefined)
}
return promise
.then((res) => {
if (isCancelled.value) {
return
}
data.value = res
error.value = false
return data.value
})
.catch((err) => {
error.value = err
throw err
if (!isCancelled.value) {
error.value = err
throw err
}
return Promise.resolve(undefined)
})
.finally(() => {
loading.value = false
@@ -54,11 +89,12 @@ export default function useRequest<T, P = undefined>(
}
const cancel = () => {
isCancelled.value = true
if (requestTask) {
requestTask.abort()
loading.value = false // Reset loading state on cancel
error.value = new Error('Request cancelled') // Set a specific error for cancellation
}
loading.value = false
error.value = new Error('Request cancelled')
}
if (options.immediate) {

View File

@@ -24,7 +24,7 @@ export function http<T>(options: CustomRequestOptions) {
// 状态码 2xx参考 axios 的设计
if (res.statusCode >= 200 && res.statusCode < 300) {
// 2.1 处理业务逻辑错误
const { code, message, msg, data } = res.data as IResponse<T>
const { code = 0, message = '', data = null } = res.data as IResponse<T>
// 0和200当做成功都很普遍这里直接兼容两者见 ResultEnum
if (code !== ResultEnum.Success0 && code !== ResultEnum.Success200) {
throw new Error(`请求错误[${code}]${message || msg}`)