AbortController 清理长连接心跳的核心是在心跳请求前检查 signal.aborted 并在连接关闭或页面卸载时主动调用 abort(),从而终止挂起 fetch 请求并清除定时器;它不自动感知网络断开,需结合失败计数或服务端状态兜底。

用 AbortController 清理长连接心跳,核心是:**在心跳请求发出前检查信号是否已中止,且在连接关闭或页面卸载时主动调用 abort()**。它不能自动感知网络断开,但能可靠终止挂起的 fetch 请求和清除后续定时任务。
心跳发起前检查 abortSignal 状态
每次发送心跳前,先判断 signal.aborted,避免无意义请求:
const controller = new AbortController();
const signal = controller.signal;
<p>function sendHeartbeat() {
if (signal.aborted) return; // 已中止,跳过本次</p><p>fetch('/api/heartbeat', { signal })
.then(res => {
if (!res.ok) throw new Error('Heartbeat failed');
setTimeout(sendHeartbeat, 30000);
})
.catch(err => {
if (err.name === 'AbortError') {
console.log('Heartbeat aborted — cleanup done');
return;
}
console.error('Heartbeat error:', err);
// 可选:失败后重试或通知上层
});
}</p><p>sendHeartbeat();
连接关闭或页面离开时主动 abort
显式调用 controller.abort() 是清理的关键,常见触发时机:
- 手动断开长连接(如用户点击“退出”)
- 监听
beforeunload或pagehide(更推荐后者,兼容后台标签页) - WebSocket 关闭、SSE 连接终止后
- 组件卸载(React useEffect cleanup / Vue onBeforeUnmount)
示例(页面隐藏时清理):
立即学习“Java免费学习笔记(深入)”;
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
window.addEventListener('pagehide', () => {
controller.abort();
});
配合 clearInterval 防止定时器泄漏
仅 abort fetch 不够——如果用 setInterval 发心跳,需同步清除定时器:
let heartbeatTimer;
<p>function startHeartbeat() {
const controller = new AbortController();
const signal = controller.signal;</p><p>function tick() {
if (signal.aborted) return;
fetch('/api/heartbeat', { signal })
.catch(() => {/<em> 忽略 AbortError </em>/});
}</p><p>heartbeatTimer = setInterval(tick, 30000);</p><p>// 清理函数
return () => {
controller.abort();
clearInterval(heartbeatTimer);
heartbeatTimer = null;
};
}</p><p>// 使用
const cleanup = startHeartbeat();</p><p>// 后续某处调用
cleanup(); // 中止请求 + 清除定时器
服务端断连后前端自动停止的补充策略
AbortController 本身不监听服务端断开,但可结合响应体或状态码做兜底:
- 心跳接口返回
204 No Content或明确的{ "status": "ok" },否则视为异常 - 连续 2–3 次失败后自动 abort(需维护失败计数)
- 搭配
WebSocket.onclose或EventSource.onerror触发统一清理
例如:
let failCount = 0;
const MAX_FAIL = 3;
<p>function sendHeartbeat() {
if (signal.aborted) return;</p><p>fetch('/api/heartbeat', { signal })
.then(res => {
if (res.status === 204) {
failCount = 0; // 重置
setTimeout(sendHeartbeat, 30000);
} else {
handleHeartbeatError();
}
})
.catch(handleHeartbeatError);
}</p><p>function handleHeartbeatError() {
failCount++;
if (failCount >= MAX_FAIL) {
controller.abort();
}
}

















