终止请求
Keq 提供两种终止请求的方式:
- 主动终止(
.abort()):持有请求实例,在业务时机直接调用。 - 响应式终止(
.abortWhen()):声明一个中止源(AbortSignal/Promise),请求会响应它的中止或完成而终止。
Keq 的请求是惰性的:request.get(...) 直到 await、.then() 或 .end() 才会真正发送。
主动终止 - .abort()
调用 .end() 立即发送请求,并保留请求实例,在任意时机中止:
import { request, AbortException } from 'keq'
const handler = request.get('/api/cats')
// end() 立即发送请求,并返回 Promise
const pending = handler.end()
// 请求进行中,由业务代码决定何时中止
handler.abort(new AbortException('用户离开页面'))
try {
await pending
} catch (err) {
if (err instanceof AbortException) {
console.error('请求已终止:', err.message)
}
}不传参数时,中止原因默认为 new AbortException('Request aborted');也支持任意值作为中止原因:
const handler = request.get('/api/cats')
handler.end()
handler.abort()
// handler.abort('user navigated away')在请求发送前调用 .abort() 同样有效:请求不会发送,await 时直接以中止原因拒绝。请求完成后调用 .abort() 不再产生任何效果。
响应式终止 - .abortWhen()
.abortWhen() 把中止时机声明为一个中止源:AbortSignal 中止、或 Promise 完成时,请求随之终止,适合与组件卸载、路由切换等异步流程联动。
AbortSignal
import { request, AbortException } from 'keq'
const controller = new AbortController()
try {
// await 时发送请求;controller 中止时请求随之中止
const cats = await request
.get('/api/cats')
.abortWhen(controller.signal)
} catch (err) {
if (err instanceof AbortException) {
console.error('请求已终止:', err.message)
}
}controller 由调用方持有(例如组件卸载、用户点击取消时调用 controller.abort(reason))。如果传入的 signal 已经中止,请求会在开始执行时立即终止;中止原因取自 signal.reason(未传原因时为默认的 DOMException,name 为 AbortError)。请求结束(成功或失败)后,abortWhen 注册的监听会被自动移除。
Promise
import { request } from 'keq'
// 例如路由变化时 resolve
const routeChanged = new Promise<void>((resolve) => {
router.afterEach(() => resolve())
})
// Promise 完成(resolve 或 reject)时终止请求
const cats = await request
.get('/api/cats')
.abortWhen(routeChanged)通过中间件中止
如果希望把中止逻辑做成可复用的能力,或者按条件中止,可以放进中间件。中间件在请求执行过程中运行,因此可以在任意阶段调用 context.abort(reason) 中止当前请求。
下面是一个按时间中止的最小示例(如果是纯超时,优先使用内置的 .timeout()):
import { request, AbortException, KeqMiddleware } from 'keq'
function abortAfter(milliseconds: number): KeqMiddleware {
return async (context, next) => {
const timer = setTimeout(() => {
context.abort(new AbortException(`请求超过 ${milliseconds}ms 未完成`))
}, milliseconds)
try {
await next()
} finally {
clearTimeout(timer)
}
}
}
await request
.get('/api/cats')
.use(abortAfter(3000))与超时、并发控制的区别
.timeout():超时后自动中止请求,并以DOMException(name为AbortError)拒绝;配置了.retry()时仍会重试。.flowControl('abort'):发送同一 key 的新请求时,自动中止旧请求。.abort()/.abortWhen():由业务代码主动控制或声明中止时机;配合中间件可以做成全局策略。