vue中单个阻断和全局阻断请求

index.vue--->在请求接口时,除了传递参数,再传递一个this过去。

import requestList from'@/api/list.js'//发出请求requestList({id:1},this).then(res=>{}).catch(err=>{})

//取消请求的写法,传进去的是提示this.cancel("操作取消");

复制代码

api/list.js---> API接口处,引入axios,定义CancelToken,写new CancelToken

import axios from'axios'constCancelToken = axios.CancelToken;

exportfunctionsearchList(data, that) {
    returnrequest({
        url: '/list',
        method: 'post',
        disLoading: true,
        data,
        cancelToken: newCancelToken(functionexecutor(c) {
            that.cancel = c;
        })
    })
}
复制代码

全局配置 | Mixin

使用vuex的mixin实现,我跟着代码打了一遍,虽然进入了cancelToken的方法,但是并没有取消请求。后续:找到没有取消请求的原因了,要注意{ cancelToken: this.cancelToken }这个东西不是请求参数,而是要放到axios config中,与url平级的。另外参考文档里只实现了销毁页面前取消请求,我举一反三——取消上一次请求操作(比如分页点击查询列表,查询第一页再点击第二页,其实是同操作方法,所以取消了第一页的pending请求)。代码如下:

/mixins/cancelTokenMixin.js --->新建一个这个mixin文件,写以下代码,只用于取消请求:

import axios from'axios';
constCancelToken = axios.CancelToken;

const cancelTokenMixin = {
    data() {
        return {
            cancelToken: null, // cancelToken实例cancel: null// cancel方法
        }
    },
    created() {
        this.newCancelToken();

    },
    beforeDestroy() {
		//离开页面前清空所有请求this.cancel('取消请求');
    },
    methods: {
		//创建新CancelTokennewCancelToken() {
            this.cancelToken = newCancelToken(c => {
                this.cancel = c;
            });
        }
    }
}
exportdefault cancelTokenMixin;
复制代码

具体vue文件--->引入mixin,在请求之前取消上次请求并创建新cancelToken

import cancelTokenMixin from"@/utils/cancelTokenMixin";
import getList from'@/api/list';

mixins: [cancelTokenMixin],

methods:{
	handleList(){
		//取消上一次请求
		this.cancel("操作取消");
		//使用新的cancelToken
		this.newCancelToken();
		//记得增加第二个参数:{ cancelToken: this.cancelToken }
		getList({id:1},{ cancelToken: this.cancelToken }).then(res=>{}).catch(err=>{})
	}
}

复制代码

api/list.js---> 接受两个参数,一个是请求参数,还有一个是config,就是上面这个:{ cancelToken: this.cancelToken }

exportfunctiongetList(data, config) {
    returnrequest({
        url: '/resource/link/getAllLink',
        method: 'post',
        disLoading: true,
        data,
        ...config
    })
}
复制代码

全局配置 | interceptors

上面使用Mixin方法不太灵活,需要在每次请求前手动调用cancelToken方法,多了就不太好用了。。参考了别人的文章,可以在axios 拦截器中实现。主要逻辑就是针对pending请求,把它们保存在set里,发出请求前取消相同的pending请求。但是这种方法有一个严重的缺点就是:它是针对同url且同参数的请求。举个例子来说就明白了——列表的分页,点击第一页时在pending中,这时点击第二页,理应应该取消第一页的pending,如果你用这个路由拦截,由于传参不一致(page=1,page=2),所以无法阻止第一页还在pending。建议这种地方需要特殊处理呢。先来看看实现方式把--->

utils/cancelRequest.js--->写三个方法。

const qs = require('qs');
const pending = newMap();
import axios from'axios';
constCancelToken = axios.CancelToken;

/**
 * 添加pending请求
 *
 * **/exportconstaddPending = (config) => {
    const url = [config.method, config.url, qs.stringify(config.params), qs.stringify(config.data)].join('&');
    config.cancelToken = config.cancelToken || newCancelToken(c => {
        if (!pending.has(url)) {
            pending.set(url, c);
        }
    })
    console.log(url);
}

/**
 * 取消单个pending请求
 * **/exportconstcancelPending = (config) => {
    const url = [config.method, config.url, qs.stringify(config.params), qs.stringify(config.data)].join('&');
    if (pending.has(url)) {
        const cancel = pending.get(url);
        cancel('cancel request');
        pending.delete(url);
    }
}
/**
 * 清空pending请求(退出页面时)
 * **/exportconstclearAllPending = () => {
    for (const [url, cancel] of pending) {
        cancel('cancel request');
    }
    pending.clear();
}


复制代码

src/utils/request.js--->拦截请求之前cancelPending和addPending,拦截返回cancelPending

import { cancelPending, addPending } from'@/utils/cancelRequest'
service.interceptors.request.use(
  config => {
    cancelPending(config) // 在请求开始前,对之前的请求做检查取消操作addPending(config) // 将当前请求添加到 pending 中return config
  },
  error => {
    console.log(error) // for debugreturnPromise.reject(error)
  }
)

service.interceptors.response.use(
  response => {
    cancelPending(response) // 在请求结束后,移除本次请求
  },
  error => {
    console.log('err', error) // for debugreturnPromise.reject(error)
  }
)
复制代码

src/permission.js--->路由守卫中清空pending的请求,这时因为离开页面了就不请求了

import { clearAllPending } from'@/utils/cancelRequest'

router.beforeEach(async (to, from, next) => {
  clearAllPending()//清空pending请求
})
复制代码

遇到的问题:我在项目里使用了‘全局配置 | interceptors’和局部取消请求的方式,已经成功实践取消请求的功能。但是遇到一个问题,第一次点击查询列表,由于我在el-table组件绑定了v-loading="listLoading",所以设置listLoading为true,以达到加载表格的效果,这时是正常的,请求pengding中,再次点击查询,还是设置了listLoading=true,接着cancel上一次请求并开启新的请求了,可是表格不再有加载效果。。。。找到原因了,原来是promise请求我写了个catch,在那里有一个listLoading=false。

作者:爱吃芒果的波波

链接:https://juejin.cn/post/7086710266502578184

来源:稀土掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值