页面关闭或刷新时,async函数执行戛然而止、未完成请求被强制中止;sendBeacon与fetch keepalive是专为此场景设计的可靠上报方案,由浏览器后台线程保障发送。

浏览器关闭或刷新时,未完成的 async 函数和网络请求不会“自动优雅收尾”,而是被强制中止——但中止方式和结果因 API 类型而异,不是所有请求都能被可靠送达。
async 函数本身不会被“中断”,但执行会戛然而止
async 函数本质是返回 Promise 的普通函数,其内部执行依赖 JavaScript 事件循环。一旦页面进入卸载(beforeunload、unload)或标签页不可见(visibilitychange)阶段,浏览器会:
- 停止调度新的宏任务(如
setTimeout回调、fetch响应处理) - 清空微任务队列(
Promise.then、async函数内await后续代码) - 销毁当前 JS 执行上下文,所有未 resolve/reject 的 Promise 永远处于 pending 状态
这意味着:即使 async 函数里写了 await fetch(...),若响应尚未返回页面就刷新了,await 后面的代码根本不会执行,try/catch 也捕获不到错误——因为 Promise 还没被 reject,它只是被遗弃了。
普通 fetch / XMLHttpRequest 请求大概率发不出去
在 unload 或 beforeunload 中发起常规异步请求,几乎必然失败:
立即学习“Java免费学习笔记(深入)”;
-
fetch()和XMLHttpRequest在页面卸载时会被浏览器主动取消,catch很难触发(部分浏览器连 reject 都不抛) - 即使请求已发出,服务端可能收到,但前端无法确认;更常见的是 TCP 连接被强制断开,请求中途夭折
-
visibilitychange(切到其他标签页)比unload稍可靠,但仍有高失败率,尤其弱网环境
真正可靠的关闭前上报:sendBeacon 与 fetch keepalive
这两个 API 是浏览器专为“页面即将消失”场景设计的底层机制,不依赖事件循环,由浏览器内核保障发送:
-
navigator.sendBeacon(url, data):仅支持 POST,数据上限约 64KB,兼容性好(IE11+),发送后立即返回true/false,无需等待响应 -
fetch(url, { method: 'POST', body: data, keepalive: true }):更灵活(支持任意 method/body 类型),但需注意:keepalive 必须显式设为true,且只在 unload 时机有效;Chrome/Firefox 支持,Safari 支持度有限
二者共同特点是:请求交由浏览器后台线程发出,即使页面 DOM 和 JS 上下文已销毁,仍尽力传输。失败时无回调,但成功率远高于普通请求。
AbortController 对关闭场景基本无效
AbortController 适用于主动取消(如用户点击“取消搜索”),但它依赖 JS 主线程正常运行:
- 页面卸载时,
controller.abort()来不及执行,signal 也没机会传播 - 即使提前在
beforeunload中调用abort(),绑定的fetch也大概率已被浏览器强制终止,AbortError不一定被捕获 - 它解决的是竞态问题,不是生命周期兜底问题


















