Maison > Article > interface Web > Parlons de la façon dont Vue empêche les requêtes répétées dans cet article
Comment vue empêche-t-il les requêtes répétées ? L'article suivant présentera deux façons permettant à Vue d'éviter les requêtes répétées. J'espère qu'il vous sera utile !
Le code front-end du projet rencontrera la situation où la même demande est envoyée plusieurs fois au serveur. Nous devons éviter de gaspiller les ressources du serveur. La même demande ne peut être envoyée qu'une seule fois dans une certaine période. de temps
(1) Si l'entreprise est simple, comme empêcher plusieurs clics sur le même bouton, nous pouvons utiliser une minuterie pour le traitement anti-tremblement
(2) Si l'entreprise est complexe, comme plusieurs composants passant par le code et la même requête étant envoyée plusieurs fois, le processus anti-shake est déjà terminé C'est difficile à gérer, il est préférable d'annuler les requêtes ajax répétées de manière unifiée
Méthode 1 - Traitement anti-tremblement via minuterie
Effet : Lorsque l'utilisateur clique plusieurs fois de suite sur le même bouton, une demande sera lancée après une courte période de temps après le dernier clic
Principe : Un minuteur est généré après l'appel de chaque méthode, et la demande sera envoyée après l'expiration du minuteur. Si l'appel répété de la méthode annulera le minuteur actuel, créera un nouveau minuteur, puis enverra la demande. après la fin. Vous pouvez utiliser des fonctions d'outils encapsulés tiers telles que la méthode debounce code> de <code>lodash
pour simplifier le code anti-tremblement [Recommandations associées : Tutoriel vidéo vuejslodash
的debounce
方法来简化防抖的代码 【相关推荐:vuejs视频教程、web前端开发】
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.min.js" type="application/javascript"></script> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript"></script> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript"></script> </head> <body> <div id="app"> <button @click="onClick">请求</button> </div> </body> <script> // 定义请求接口 function sendPost(data){ return axios({ url: 'https://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', method: 'post', data }) } new Vue({ el: '#app', methods: { // 调用lodash的防抖方法debounce,实现连续点击按钮多次,0.3秒后调用1次接口 onClick: _.debounce(async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求的结果', res.data) }, 300), }, }) </script> </html>
无法解决多个按钮件的重复请求的发送问题,例如下面两种情况
按钮事件间是相互独立的,调用的是不同方法,做不到按钮间防抖效果
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.min.js" type="application/javascript"></script> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript"></script> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript"></script> </head> <body> <div id="app"> <button @click="onClick1" ref="btn1">请求1</button> <button @click="onClick2" ref="btn2">请求2</button> </div> </body> <script> let sendPost = function(data){ return axios({ url: 'http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', method: 'post', data }) } new Vue({ el: '#app', mounted() { this.$refs.btn1.click() this.$refs.btn2.click() }, methods: { // 使用lodash对请求方法做防抖 //这里有问题,只是对每个按钮的点击事件单独做了防抖,但是两个按钮之间做不到防抖的效果 onClick1: _.debounce(async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求1的结果', res.data) }, 300), onClick2: _.debounce(async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求2的结果', res.data) }, 300), }, }) </script> </html>
按钮间调用的方法是相同的,是可以对方法做防抖处理,但是处理本身对方法做了一次封装,会影响到之前方法的返回值接收,需要对之前的方法做更多处理,变得更加复杂,不推荐
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.min.js" type="application/javascript"></script> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript"></script> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript"></script> </head> <body> <div id="app"> <button @click="onClick1" ref="btn1">请求1</button> <button @click="onClick2" ref="btn2">请求2</button> </div> </body> <script> // 使用lodash对请求方法做防抖, let sendPost = _.debounce(function(data){ //这里有问题,这里的返回值不能作为sendPost方法执行的返回值,因为debounce内部包裹了一层 return axios({ url: 'http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', method: 'post', data }) }, 300) new Vue({ el: '#app', mounted() { this.$refs.btn1.click() this.$refs.btn2.click() }, methods: { onClick1: async function(){ //这里有问题,sendPost返回值不是promise,而是undefined let res = await sendPost({username:'zs', age: 20}) console.log('请求1的结果', res) }, onClick2: async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求2的结果', res) }, }, }) </script> </html>
方式2-通过取消ajax请求
直接对请求方法做处理,通过ajax库的api方法把重复的请求给取消掉
通过调用XMLHttpRequest
对象实例的abort
方法把请求给取消掉
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> </body> <script> //原生ajax的语法 let xhr = new XMLHttpRequest(); xhr.open("GET", "http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test?username=zs&age=20", true); xhr.onload = function(){ console.log(xhr.responseText) } xhr.send(); //在谷歌浏览器的低速3g下面测试 //通过XMLHttpRequest实例的abort方法取消请求 setTimeout(() => xhr.abort(), 100); </script> </html>
通过axios
的CancelToken
对象实例cancel
方法把请求给取消掉
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript"></script> </head> <body> </body> <script> /*axios的取消的语法*/ // 方式1-通过axios.CancelToken.source产生cancelToken和cancel方法 /* const source = axios.CancelToken.source(); axios.get('http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', { params: {username: 'zs', age: 20}, cancelToken: source.token }).then(res=>{ console.log('res', res.data) }).catch(err=>{ console.log('err', err) }) //在谷歌浏览器的低速3g下面测试 //通过调用source的cancel方法取消 setTimeout(() => source.cancel(), 100); */ /**/ // 方式2-通过new axios.CancelToken产生cancelToken和cancel方法 let cancelFn const cancelToken = new axios.CancelToken(cancel=>{ cancelFn = cancel }); axios.get('http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', { params: {username: 'zs', age: 20}, cancelToken: cancelToken }).then(res=>{ console.log('res', res.data) }).catch(err=>{ console.log('err', err) }) //在谷歌浏览器的低速3g下面测试 //通过调用cancelFn方法取消 setTimeout(() => cancelFn(), 100); </script> </html>
通过axios
请求拦截器,在每次请求前把请求信息和请求的取消方法放到一个map对象当中,并且判断map对象当中是否已经存在该请求信息的请求,如果存在取消上传请求
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript"></script> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript"></script> <script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/qs/6.10.3/qs.js" type="application/javascript"></script> </head> <body> <div id="app"> <button @click="onClick1" ref="btn1">请求1</button> <button @click="onClick2" ref="btn2">请求2</button> </div> </body> <script> //存储请求信息和取消方法的的map对象 const pendingRequest = new Map(); //根据请求的信息(请求方式,url,请求get/post数据),产生map的key function getRequestKey(config){ const { method, url, params, data } = config; return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&"); } //请求拦截器 axios.interceptors.request.use( function (config) { //根据请求的信息(请求方式,url,请求get/post数据),产生map的key let requestKey = getRequestKey(config) //判断请求是否重复 if(pendingRequest.has(requestKey)){ //取消上次请求 let cancel = pendingRequest.get(requestKey) cancel() //删除请求信息 pendingRequest.delete(requestKey) } //把请求信息,添加请求到map当中 // 生成取消方法 config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => { // 把取消方法添加到map if (!pendingRequest.has(requestKey)) { pendingRequest.set(requestKey, cancel) } }) return config; }, (error) => { return Promise.reject(error); } ); let sendPost = function(data){ return axios({ url: 'http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', method: 'post', data }) } new Vue({ el: '#app', mounted() { this.$refs.btn1.click() this.$refs.btn2.click() }, methods: { // 使用lodash对请求方法做防抖 //这里有问题,只是对每个按钮的点击事件单独做了防抖,但是两个按钮之间做不到防抖的效果 onClick1: async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求1的结果', res.data) }, onClick2: async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求2的结果', res.data) }, }, }) </script> </html>
通过axios
, développement web front-end
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript"></script> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript"></script> <script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/qs/6.10.3/qs.js" type="application/javascript"></script> </head> <body> <div id="app"> <button @click="onClick1" ref="btn1">请求1</button> <button @click="onClick2" ref="btn2">请求2</button> </div> </body> <script> //存储请求信息和取消方法的的map对象 const pendingRequest = new Map(); //根据请求的信息(请求方式,url,请求get/post数据),产生map的key function getRequestKey(config){ const { method, url, params, data } = config; return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&"); } //请求拦截器 axios.interceptors.request.use( function (config) { //根据请求的信息(请求方式,url,请求get/post数据),产生map的key let requestKey = getRequestKey(config) //判断请求是否重复 if(pendingRequest.has(requestKey)){ //取消上次请求 let cancel = pendingRequest.get(requestKey) cancel() //删除请求信息 pendingRequest.delete(requestKey) } //把请求信息,添加请求到map当中 // 生成取消方法 config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => { // 把取消方法添加到map if (!pendingRequest.has(requestKey)) { pendingRequest.set(requestKey, cancel) } }) return config; }, (error) => { return Promise.reject(error); } ); //响应拦截器 axios.interceptors.response.use( (response) => { //请求成功 //删除请求的信息 let requestKey = getRequestKey(response.config) if(pendingRequest.has(requestKey)){ pendingRequest.delete(requestKey) } return response; }, (error) => { return Promise.reject(error); } ); let sendPost = function(data){ return axios({ url: 'http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', method: 'post', data }) } new Vue({ el: '#app', mounted() { this.$refs.btn1.click() this.$refs.btn2.click() }, methods: { // 使用lodash对请求方法做防抖 //这里有问题,只是对每个按钮的点击事件单独做了防抖,但是两个按钮之间做不到防抖的效果 onClick1: async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求1的结果', res.data) }, onClick2: async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求2的结果', res.data) }, }, }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript"></script> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript"></script> <script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/qs/6.10.3/qs.js" type="application/javascript"></script> </head> <body> <div id="app"> <button @click="onClick1" ref="btn1">请求1</button> <button @click="onClick2" ref="btn2">请求2</button> </div> </body> <script> //存储请求信息和取消方法的的map对象 const pendingRequest = new Map(); //根据请求的信息(请求方式,url,请求get/post数据),产生map的key function getRequestKey(config){ const { method, url, params, data } = config; return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&"); } //请求拦截器 axios.interceptors.request.use( function (config) { //根据请求的信息(请求方式,url,请求get/post数据),产生map的key let requestKey = getRequestKey(config) //判断请求是否重复 if(pendingRequest.has(requestKey)){ //取消上次请求 let cancel = pendingRequest.get(requestKey) cancel() //删除请求信息 pendingRequest.delete(requestKey) } //把请求信息,添加请求到map当中 // 生成取消方法 config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => { // 把取消方法添加到map if (!pendingRequest.has(requestKey)) { pendingRequest.set(requestKey, cancel) } }) return config; }, (error) => { return Promise.reject(error); } ); //删除请求信息 function delPendingRequest(config){ let requestKey = getRequestKey(config) if(pendingRequest.has(requestKey)){ pendingRequest.delete(requestKey) } } //响应拦截器 axios.interceptors.response.use( (response) => { //请求成功 //删除请求的信息 delPendingRequest(response.config) return response; }, (error) => { //请求失败 //不是取消请求的错误 if (!axios.isCancel(error)){ //服务器报400,500报错,删除请求信息 delPendingRequest(error.config || {}) } return Promise.reject(error); } ); let sendPost = function(data){ return axios({ url: 'http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', method: 'post', data }) } new Vue({ el: '#app', mounted() { this.$refs.btn1.click() this.$refs.btn2.click() }, methods: { // 使用lodash对请求方法做防抖 //这里有问题,只是对每个按钮的点击事件单独做了防抖,但是两个按钮之间做不到防抖的效果 onClick1: async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求1的结果', res.data) }, onClick2: async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求2的结果', res.data) }, }, }) </script> </html>🎜Aperçu 🎜🎜
abort
de l'instance d'objet XMLHttpRequest
🎜rrreee🎜Aperçu 🎜 🎜demande d'annulation d'axios🎜Grâce à l'instance d'objet CancelToken
méthode cancel
de axios
Annuler la demande🎜rrreee🎜Aperçu 🎜🎜axios
, placez les informations de la demande et la méthode d'annulation demandée dans un objet cartographique avant chaque requête et déterminez si l'objet cartographique a été Il y a une demande de cette information de demande S'il y a une demande d'annulation du téléchargement🎜rrreee🎜Aperçu 🎜🎜axios
, une fois la requête réussie, supprimez les données des informations de la requête dans l'objet cartographique🎜rrreee🎜🎜Aperçu🎜🎜通过axios
的响应拦截器,在请求失败后在map对象当中,删除该请求信息的数据
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript"></script> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript"></script> <script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/qs/6.10.3/qs.js" type="application/javascript"></script> </head> <body> <div id="app"> <button @click="onClick1" ref="btn1">请求1</button> <button @click="onClick2" ref="btn2">请求2</button> </div> </body> <script> //存储请求信息和取消方法的的map对象 const pendingRequest = new Map(); //根据请求的信息(请求方式,url,请求get/post数据),产生map的key function getRequestKey(config){ const { method, url, params, data } = config; return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&"); } //请求拦截器 axios.interceptors.request.use( function (config) { //根据请求的信息(请求方式,url,请求get/post数据),产生map的key let requestKey = getRequestKey(config) //判断请求是否重复 if(pendingRequest.has(requestKey)){ //取消上次请求 let cancel = pendingRequest.get(requestKey) cancel() //删除请求信息 pendingRequest.delete(requestKey) } //把请求信息,添加请求到map当中 // 生成取消方法 config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => { // 把取消方法添加到map if (!pendingRequest.has(requestKey)) { pendingRequest.set(requestKey, cancel) } }) return config; }, (error) => { return Promise.reject(error); } ); //删除请求信息 function delPendingRequest(config){ let requestKey = getRequestKey(config) if(pendingRequest.has(requestKey)){ pendingRequest.delete(requestKey) } } //响应拦截器 axios.interceptors.response.use( (response) => { //请求成功 //删除请求的信息 delPendingRequest(response.config) return response; }, (error) => { //请求失败 //不是取消请求的错误 if (!axios.isCancel(error)){ //服务器报400,500报错,删除请求信息 delPendingRequest(error.config || {}) } return Promise.reject(error); } ); let sendPost = function(data){ return axios({ url: 'http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', method: 'post', data }) } new Vue({ el: '#app', mounted() { this.$refs.btn1.click() this.$refs.btn2.click() }, methods: { // 使用lodash对请求方法做防抖 //这里有问题,只是对每个按钮的点击事件单独做了防抖,但是两个按钮之间做不到防抖的效果 onClick1: async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求1的结果', res.data) }, onClick2: async function(){ let res = await sendPost({username:'zs', age: 20}) console.log('请求2的结果', res.data) }, }, }) </script> </html>
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!