震惊~img.src竟然还能这样用?——关于关闭页签时调用接口的解决方案

1,008 阅读2分钟

前言

在进行开发时遇到一个小问题,就是在用户关闭页签时如果某个状态是开启时那么就调用关闭接口。很简单的一个需求,它还能翻起什么浪花呢~

问题

onMounted(() => {
    // 添加 beforeunload 事件监听器
    window.addEventListener('beforeunload', handleCarBeforeUnload);
});

// 处理 beforeunload 事件
const handleCarBeforeUnload = (event) => {
    // 只有开启状态退出时执行关闭
    if (data.deviceStatus) {
        API.closeDevice();
    }
};
onBeforeUnmount(() => {
    // 添加 beforeunload 事件监听器
    window.removeEventListener('beforeunload', handleCarBeforeUnload);
});

简单,这样不就行了,然后->测试->失败。嘻嘻,md。
什么情况难道是没触发?,那就debugger下看看, 结果是进入了, 那就奇怪了

那只能祭出无上AI大法了,于是得到了以下的结果

在 beforeunload 事件中使用 axios 调用接口可能会失败,原因主要有以下几点:

  • 1. 页面卸载时异步请求不可靠
    • 当页面开始卸载时,浏览器会逐步终止页面的 JavaScript 执行环境,包括未完成的异步请求(如 axios 的 HTTP 请求)。
    • axios 是基于 XMLHttpRequest 或 fetch 的异步请求库,而异步请求在页面卸载时可能被浏览器直接中断,导致请求无法完成。
  • 2. beforeunload 事件的限制

    • beforeunload 事件的主要目的是提示用户是否确认离开页面,而不是用于执行复杂的逻辑(如发送请求)。
    • 浏览器可能会限制 beforeunload 事件中的代码执行时间,以确保页面能够快速卸载。
  • 3. 解决方案:使用 navigator.sendBeacon

    • navigator.sendBeacon 是专门为页面卸载时发送数据设计的,它会在页面卸载时异步发送数据,且不会被浏览器中断。

    • 将 axios 替换为 navigator.sendBeacon,可以确保请求成功发送。

    • 示例代码:

window.addEventListener('beforeunload', handleCarBeforeUnload);

function handleCarBeforeUnload() {
  const data = JSON.stringify({ event: 'page_unload', time: Date.now() });
  navigator.sendBeacon('/your-endpoint', data);
}

那就试试呗, 修改->测试->失败。嘻嘻,md

解决

使用navigator.sendBeacon()方法不行主要是此方法为post请求,而我需要调用的是一个get方法,那既然不能一步就尝试一下写个同步请求

const xhr = new XMLHttpRequest();
xhr.open('GET', '/your-api, false); // 同步请求
xhr.send();

嗯,不出意外->测试->失败。嘻嘻,md 我感觉主要是因为这个

浏览器可能会限制 beforeunload 事件中的代码执行时间,以确保页面能够快速卸载。

既然不行那真的是天要亡我吗,这点小问题就难住了,不行我得继续我的无上AI大法,于是就有了下面这个最终版的方法.

// 处理 beforeunload 事件
const handleCarBeforeUnload = (event) => {
    // 只有开启状态退出时执行关闭
    if (data.deviceStatus) {
        const params = new URLSearchParams({
            force: true,
            _t: Date.now() // 防止缓存
        });
        // 方案1:使用 Image 对象(最可靠)
        const img = new Image();
        img.src = `/your-api?${params}`;
    }
};

嗯,它是怎么能想到的呢 -.-

结语

至此就告一段落了,不得不说新脑子就是转得快啊~