欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JS使用axios取消请求 - Kaiqisan

程序员文章站 2022-06-18 14:08:18
JS使用axios取消请求ヤッハロー、Kaiqisanすうう、一つふつうの学生プログラマである,这一次也是直面项目上遇到的问题,这次内容有点多,如果您只是想复制代码的话,我做个目录,直接跳到目录找代码即可。文章目录JS使用axios取消请求官网写的取消法取消方法2更加高度的封装,使用axios.create之后的取消方法总结前端单方面违约取消请求,所以,这里的代码只有前端的事情。官网写的取消法/* a.js */import axios from 'axios'let CancelTo...

JS使用axios取消请求

ヤッハロー、Kaiqisanすうう、一つふつうの学生プログラマである,这一次也是直面项目上遇到的问题。

这次内容有点多,如果您只是想复制代码的话,我做个目录,直接跳到目录找代码即可。


前端单方面违约取消请求,所以,这里的代码只有前端的事情。

官网写的取消法

/* a.js */
import axios from 'axios'

let CancelToken = axios.CancelToken
let source = CancelToken.source()


export default {
    getReq() {
        axios({
            methods: 'get',
            url: 'http://localhost:3000/testGet', 
            // 本地写了简易服务器,设置延时处理请求模拟网卡的情况,大家有能力的可以自己写一个服务器
            cancelToken: source.token	// 关键代码
        }).then(res => {
            console.log(res)
        }).catch(err => {
            console.log(err)
        })
    },

    cancelReq() {
        source.cancel('do cancel')
        source = CancelToken.source()	// 重新规划
    }
}

这些代码直接下载.vue .jsx文件中也可以,只要参数到位,找到合适的机会触发就可以了。

PS:上面的取消操作是AOE影响的,意思就是说它可以一次取消多次请求,如果一个人在短时间内发起多次请求,后端没来得及处理,让未处理的请求排起了队伍,一个取消操作就可以取消所有还未返回的请求。

///

现在我们来扒一下它的源码,康康这个过程是怎么样的呢!?

CancelToken = axios.CancelToken 

首先针对这句话来展开研究。

我们在输出栏打开源码,看到的是以下内容

function CancelToken(executor) {
  if (typeof executor !== 'function') {		// 非法情况处理
    throw new TypeError('executor must be a function.');
  }

  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;		// 通过外部来影响这个异步函数的去向
  });

  var token = this;
  executor(function cancel(message) {
    if (token.reason) {		// 如果已经取消了,就不再执行第二次'取消请求'
      return;
    }

    token.reason = new Cancel(message);
    resolvePromise(token.reason); // 成功取消请求,返回参数reason
  });
}

/**
 * Throws a `Cancel` if cancellation has been requested.
 */
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
  if (this.reason) {	
    throw this.reason;	// 
  }
};

/**
 * Returns an object that contains a new `CancelToken` and a function that, when called,
 * cancels the `CancelToken`.
 */
CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};

module.exports = CancelToken;

然后是第二句话,source = CancelToken.source(),它对于上面源码的最后一个函数,通过打印,我们可以看到这个CancelToken.source()返回了一个对象,它有俩成员,一个是token异步函数(原型是Promise),一个是cancel方法。

然后基本的命名都OK了,接下来就可以正式投入使用了。

在请求中触发了cancel()方法之后,这个方法被执行(自己去上面源码找)

function cancel(message) {
    if (token.reason) {		// 如果已经取消了,就不再执行第二次'取消请求'
      return;
    }

    token.reason = new Cancel(message);
    resolvePromise(token.reason); // 成功取消请求,返回参数reason
}

然后触发resolvePromise,走then路线

if (config.cancelToken) { // 检测原生的请求里是否有cancelToken,如果没有就不执行下面的方法
	config.cancelToken.promise.then(function onCanceled(cancel) {
		if (!request) {		// 没有请求直接劝退
			return;
		}
		request.abort();	// 原生的取消请求方法
		reject(cancel);		// 请求那边走catch路线,返回cancel参数
    	// 复位数据
		request = null;		// 清空请求
	});
}

至于在取消请求之后再次调用CancelToken.source() 复位的问题,如果不复位的话,下次再发请求的话就会直接取消,因为此时的CancelToken凭证已经被触发,想要验证的话可以在请求取消前后查看CancelToken.source(),我们会发现在请求取消后,它的token参数中多了一个reason属性。这就表示请求已经被取消。凭证是一次性的,如果发现凭证有reason属性,就表示需要取消请求。所以需要复位。

取消方法2

上面已经讲了原理,下面就不会再详细展开

/* a.js */
import axios from 'axios'

let CancelToken = axios.CancelToken
let cancel		// 取消参数


export default {
    getReq() {
        axios({
            methods: 'get',
            url: 'http://localhost:3000/testGet', 
            // 本地写了简易服务器,设置延时处理请求模拟网卡的情况,大家有能力的可以自己写一个服务器
            cancelToken: new CancelToken(function executor(c) { 
    			cancel = c;
  			}) // 等同于上面的 source.token
        }).then(res => {
            console.log(res)
        }).catch(err => {
            console.log(err)
        })
    },

    cancelReq() {
        cancel('do cancel')
    }
}

PS:executor函数内的参数c为函数

function cancel(message) {
    if (token.reason) {		// 如果已经取消了,就不再执行第二次'取消请求'
      return;
    }

    token.reason = new Cancel(message);
    resolvePromise(token.reason); // 成功取消请求,返回参数reason
}

它只能拦截当前请求,无法拦截所有已经发出去的请求,所以在开发的时候请做好防滑操作!

更加高度的封装,使用axios.create之后的取消方法

/* 配置文件 */
import axios from 'axios'

// 创建axios实例
const service = axios.create({
    baseURL: configJS.BASE_API,
})


// request拦截器
service.interceptors.request.use(
    ...........// 请求拦截
)

// respone拦截器
service.interceptors.response.use(
    ............
)

export default service

配置文件就正常创建

/* api仓库 */
import axios from 'axios'
import request from '@/utils/request'	// axios配置文件

getInfo(data, that) {
    return request({
        url: 'xxxxxxxx', // 自己定
        method: 'get',	// 只适合get请求的取消
        params: data,	// 参数
        cancelToken: new axios.CancelToken(function executor(c) {
            that.source = c
        })
    })
},
/* 开始正式调用 */

exeGetInfo() {
    api.getInfo({ id: 10 }, this).then(res => {
		.........
	}).catch(err => {
	   	........
	})
}

cancelQuest() {
    if (typeof this.source === 'function') {
        this.source('终止请求') //取消请求
    }
},

后来,我就在思索这个中断请求的原理,本来以为是前端再次向后端发送一个拒收的请求,但是,我打开服务器之后,发现在取消请求的时候并没有再一次收到第二条请求,所以,我就怀疑是前端自己直接拒收后端发来的请求。

下面是我的后端node.js代码

/* index.js主入口文件 */

const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const cors = require('cors');


let router = require('./routes/routers')


app.all('*', function(req, res, next) {
	console.log(req.method);
	res.header("Access-Control-Allow-Origin", "*");
	res.header('Access-Control-Allow-Headers', 'Content-type');
	res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS,PATCH");
	res.header('Access-Control-Max-Age', 1728000); //预请求缓存20天
	next();
});
app.use(cors({
	origin: ['http://localhost:8800'],
	methods: ['GET', 'POST'],
	allowHeader: ['Content-Type', 'Authorization']
}))
app.use(bodyParser.urlencoded({
	extended: false
}))
app.use(bodyParser.json())

app.use(router)

app.listen(3000, () => {
	console.log('服务器启动')
})
/* routers.js路由文件 */

const express = require('express')
const router = express.Router()

router.get('/testGet', (req, res) => {
    setTimeout(() => { // 增加处理时间,便于测试setTimeout
        console.log('gggggggggggggg');
        res.json([		// 返回的信息
            {
                name: 'Kaiqisan',uid: 100
            },
            {
                name: 'Tom',uid: 101
            }
        ])
    }, 3000)
})

module.exports = router

后来发现,即使我取消了请求,后端还是会向前端发送信息,那就是说我前端拒收之后后端发来什么,我都不会去理会,直接丢弃。在axios方法这里,直接走catch路线,报错完事,方法结束了。所以,以此类推,这个方法只能取消get请求,而不会取消post等其他需要后端对后台数据做出修改操作的请求,除非在触发取消操作的时候再次要求后端取消相关的操作。

总结

取消请求是很重要的方法,虽然不会减少后端的负担(服务器:我谢谢你!),但是,可以显著减少前端的内存消耗,更少的请求代表更少的捕获数据次数,也代表更少的无用数据渲染和赋值,也会适量减轻前端项目工程的复杂度,再配合防滑锁,完美!

本文地址:https://blog.csdn.net/qq_33933205/article/details/108127541

相关标签: js知识库