您好,登錄后才能下訂單哦!
本篇內容介紹了“vue如何阻止重復請求”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
項目當中前端代碼會遇到同一個請求向服務器發了多次的情況,我們要避免服務器資源浪費,同一個請求一定時間只允許發一次請求
(1)如果業務簡單,例如同一個按鈕防止多次點擊,我們可以用定時器做防抖處理
(2)如果業務復雜,例如多個組件通過代碼,同一個請求發多次,這個時候防抖已經不好處理了,最好是對重復的ajax請求統一做取消操作
方式1-通過定時器做防抖處理
效果:當用戶連續點擊多次同一個按鈕,最后一次點擊之后,過小段時間后才發起一次請求
原理:每次調用方法后都產生一個定時器,定時器結束以后再發請求,如果重復調用方法,就取消當前的定時器,創建新的定時器,等結束后再發請求,工作當中可以用第三方封裝的工具函數例如lodash
的debounce
方法來簡化防抖的代碼
<!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
的響應攔截器,在請求成功后在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);
}
);
//響應攔截器
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>
預覽
通過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>
“vue如何阻止重復請求”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。