vue3.0 前端主动中断网络请求方法

124 阅读2分钟

项目开发中有时遇到网络请求时间过长导致 pending, 需要主动去中断网络请求。例如在搜索框远程搜索数据,由于数据量比较大,搜索比较慢,设计当鼠标失去焦点时主动中段网络请求,以便进行其它操作。 在 JavaScript 中,前端可以通过 AbortController 来主动中断网络请求。AbortController 是一个全局对象,它允许你创建一个信号(signal),可以传递给许多API,包括 fetch,来中止请求。 代码如下:



const controller = new AbortController();
const signal = controller.signal;

// 请求网络数据函数
const fetchWithToken = (url:any) => {
    const headers = new Headers({
        'Authorization': `Bearer ${useUserStore().token}`,
    });

    const fetchOptions = {
        method: 'GET', // 使用适当的 HTTP 方法
        headers: headers,
        signal: controller.signal, // 将 signal 传递给 fetch
    };

    fetch(url, fetchOptions)
        .then((response: any) => {
            if (!response.ok) {
                throw new Error('网络请求失败');
            }
            return response.json(); // 将响应数据转换为 JSON
        })
        .then(data => {
          // 返回数据处理
           console.log(data)
        })
        .catch(error => {
            if (error.name === 'AbortError') {
                console.log('Fetch aborted, retrying...');
            } else {
                console.error('Fetch error:', error);
            }
        })
};

// 如果你想中断请求,可以调用controller.abort()
// fetchPromise将会 reject,并抛出一个AbortError
controller.abort();

在具体项目中的代码使用如下:

const controller = new AbortController();
const signal = controller.signal;

// 请求网络数据函数
const fetchWithToken = () => {
    const headers = new Headers({
        'Authorization': `Bearer ${useUserStore().token}`,
    });

    const fetchOptions = {
        method: 'GET', // 使用适当的HTTP方法
        headers: headers,
        signal: controller.signal, // 将signal传递给fetch
    };

    fetch(import.meta.env.VITE_AXIOS_BASEURL + '/' + Url.brandAndPartNo + '?brand=&partNo=' + searchKeyword, fetchOptions)
        .then((response: any) => {
            if (!response.ok) {
                throw new Error('网络请求失败');
            }
            return response.json(); // 将响应数据转换为JSON

        })
        .then(data => {
            // 数据处理
        })
        .catch(error => {
            if (error.name === 'AbortError') {
                console.log('Fetch aborted, retrying...');
                // fetchWithToken();
            } else {
                console.error('Fetch error:', error);
            }
        })
};

// 输入关键字搜索,调用 fetchWithToken 方法
const searchPartNo = async (keyword: any) => {
    if (!keyword || keyword.length < 3) {
        return
    }
    partNos.value = []
    spinning.value = true
    searchKeyword = keyword.toUpperCase()
    fetchWithToken()
}

// 失去焦点时触发
const onBlur = () => {
  // 中断网络请求
    controller.abort()
};

这样确实在失去焦点时主动中断了网络请求,但是会产生一个 bug, 就是我再次发起网络请求时失效。网络不会发起请求,查找原因发现是因为在 controller.abort() 中断网络请求后,signal.aborted 参数被设置为了 true,表示已经中断,所以再次调用 fetchWithToken 函数是无效的,由于这个参数是只读,不能对其更改,所以解决办法就是重新创建 AbortController。新的 signal.aborted 就恢复为了 false。

代码修改如下:

// 把 controller 设置为变量,初始化为 null
let controller:any = null
// 输入关键字搜索
const searchPartNo = async (keyword: any) => {
    if (!keyword || keyword.length < 3) {
        return
    }
    // 如果 controller 不为 null,就将 controller 初始化
    if(controller){
        controller.abort()
        controller = null
    }
    // 否则就创建新的 AbortController 赋值
    controller = new AbortController()
    partNos.value = []
    spinning.value = true
    searchKeyword = keyword.toUpperCase()
    fetchWithToken()
}

这样修改就解决了网络请求中断后,再次请求无效的问题。