DEV Community

yinjialu
yinjialu

Posted on

2行代码,解决静态冲突,自动帮你取消重复的过期请求

Image description

安装

npm i --save abort-request
Enter fullscreen mode Exit fullscreen mode

使用方式

  • 避免竞态冲突,detail 总是最新值

    原始写法

    import { watch, ref, unref } from 'vue';
    
    // 请求方法
    const getDataAPI = ({ params }: { params: { id: string } }) => {
        // 发起请求
    };
    
    const id = ref();
    const detail = ref();
    
    // 调用请求方法,handleQuery 可能多次调用,detail 数据是最新的吗?
    
    const handleQuery = () => {
    
        getDataAPI({ params: { id: unref(id) } }).then((res) => {
            detail.value = res;
        });
    };
    
    watch(id, () => {
        handleQuery();
    });
    

    2行代码优化

    import { watch, ref, unref } from 'vue';
    import { createAutoAbortExpiredRequest, isAbortError } from 'abort-request';
    
    // 请求方法
    const getDataAPI = ({ params }: { params: { id: string } }) => {
        // 发起请求
    };
    
    const id = ref();
    const detail = ref();
    
    // 创建这个请求方法的自动取消版本
    const getDataAPIAutoAbort = createAutoAbortExpiredRequest(getDataAPI);
    const handleQuery = () => {
        // 使用 getDataAPIAutoAbort 替代 getDataAPI 进行调用,传参方式不变
        getDataAPIAutoAbort({ params: { id: unref(id) } }).then((res) => {
            detail.value = res;
        });
    };
    
    watch(id, () => {
        handleQuery();
    });
    
  • 避免阻塞浏览器 - 如果旧请求还未完成,就取消

    XHR 和 Fetch 都支持传入 signal 用于中止请求,可以按照当前项目的封装方式,确定传入 signal 的方法,axios 配置参考:signal: new AbortController().signal

    const getDataAPI = ({
        params,
        signal,
    }: {
        params: { id: string };
        signal?: AbortSignal;
    }) => {
        // 发起请求
    };
    
    const handleQuery = () => {
        // getDataAPIAutoAbort 可以接受一个函数作为参数,这个函数接受 signal 参数,组装好 signal 后,返回一个数组,用做请求参数
        getDataAPIAutoAbort(({ signal }) => [
            { params: { id: unref(id) }, signal },
        ]).then((res) => {
            // 当多次调用时,未完成的请求被自动取消,不会进入 then 逻辑
            detail.value = res;
        });
    };
    
  • 处理 loading 状态

    const handleQuery = () => {
        loading.value = true;
        getDataAPIAutoAbort(({ signal }) => [{ params: { id: unref(id) }, signal }])
            .then((res) => {
                // 当多次调用时,未完成的请求被自动取消,不会进入 then 逻辑
                detail.value = res;
                loading.value = false;
            })
            .catch((err) => {
                // 判断不是取消请求的错误
                if (!isAbortError(err)) {
                    loading.value = false;
                }
            });
    
        // 不能在 finally 中处理 loading 状态
    };
    

Top comments (0)