美文网首页javascript
js路由跳转时放弃正在pending的请求

js路由跳转时放弃正在pending的请求

作者: 仰望天空的人 | 来源:发表于2021-12-29 10:56 被阅读0次

在单页面应用中通常会对请求进行catch处理,如果用户打开a页面后页面发出了一个请求去获取aaa,但是由于某种原因请求一直在pending。此时用户又进入了b页面,在浏览时a页面的请求失败了,然后页面弹出提示:“数据aaa请求失败”。这就很尴尬了。虽然在对于a页面没什么问题,但是对于b页面来说这就是无用的提示。这时就需要在跳转页面时杀掉正在pending的请求了

axios的cancelToken

https://www.kancloud.cn/yunye/axios/234845

使用 cancel token 取消请求
可以使用 CancelToken.source 工厂方法创建 cancel token,像这样:

var CancelToken = axios.CancelToken;
var source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // 处理错误
  }
});

// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');

还可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:

var CancelToken = axios.CancelToken;
var cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函数接收一个 cancel 函数作为参数
    cancel = c;
  })
});

// 取消请求
cancel();

vue路由跳转时cancel请求

定义请求services.js

import axios from 'axios';

const url = 'http://localhost:3001';

export function AApi() {
  return axios.get(`${url}/a`);
}

export function BApi() {
  return axios.get(`${url}/b`);
}

export function CApi() {
  return axios.get(`${url}/c`, {
    cancelToken: null, // 避免被加入cancel队列
  });
}

定义axios拦截器设置cancelToken

export * from './services';

import axios from 'axios';

const cancelTokenSources = new Map(); // 定义cancel队列

axios.interceptors.request.use(config => { // 请求拦截器中将请求加入cancel队列
  if (!config.hasOwnProperty('cancelToken')) { // 排除不需要cancel的请求
    const source = axios.CancelToken.source();

    cancelTokenSources.set(source.token, source.cancel); // 加入cancel队列
    config.cancelToken = source.token;
  }

  return config;
}, error => Promise.reject(error));

axios.interceptors.response.use(res => { // 响应拦截器中从cancel队列中移除
  if (res.config.cancelToken) {
    cancelTokenSources.delete(res.config.cancelToken);
  }

  return res;
}, error => {
  if (axios.isCancel(error)) {
    cancelTokenSources.delete(error.message)
  }
  return Promise.reject(error)
});

export default cancelTokenSources;

将需要放弃的请求加入cancel队列

定义路由router.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
import cancelTokenSources from './api';

Vue.use(Router);

const router = new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: About
    }
  ]
});

router.afterEach(() => { // 路由跳转杀请求
  for (const [cancelToken, cancel] of cancelTokenSources) {
    cancel(cancelToken); // cancel 正在pending的请求
  }
});

export default router;

路由跳转时对cancel队列进行遍历kill

定义about页面,放出请求

<template>
  <div class="about">
    <h1>This is an about page</h1>
  </div>
</template>

<script>
  import { AApi, BApi, CApi } from '../api';
  import axios from 'axios';

  export default {
    name: 'about',
    mounted() {
      AApi().catch(err => {
        if (axios.isCancel(err)) {
          console.log('请求被关闭了');
        } else {
          console.log('请求出问题了');
        }
      });

      BApi().catch(err => {
        if (axios.isCancel(err)) {
          console.log('请求被关闭了');
        } else {
          console.log('请求出问题了');
        }
      });

      CApi().catch(err => {
        if (axios.isCancel(err)) {
          console.log('请求被关闭了');
        } else {
          console.log('请求出问题了');
        }
      });
    }
  }
</script>

效果图

进入about页面

在这里插入图片描述

跳转至其他页面

image

由于c接口加入了cancelToken: null, 所以不会被杀掉。a和b状态已经变为canceled。


在这里插入图片描述

相关文章

网友评论

    本文标题:js路由跳转时放弃正在pending的请求

    本文链接:https://www.haomeiwen.com/subject/ydivtrtx.html