ホームページ > 記事 > ウェブフロントエンド > この記事では、Vue がリクエストの繰り返しをどのように防ぐかについて説明します。
vue はどのようにしてリクエストの繰り返しを防ぐのでしょうか?次の記事では、Vue でリクエストの繰り返しを防ぐ 2 つの方法を紹介します。
プロジェクトのフロントエンド コードでは、同じリクエストがサーバーに複数回送信される状況が発生します。サーバー リソースの無駄を避ける必要があります。同じリクエストは次のとおりです。リクエスト
(1) 複数のクリックを防ぐなど、単純なビジネスの場合同じボタンを押すと、手ぶれ補正処理にタイマーを使用できます
(2) ビジネスが複雑な場合、たとえば、複数のコンポーネントがコードを通過し、同じリクエストが複数回送信される場合、手ぶれ補正は機能しません。現時点では、繰り返される Ajax リクエストを統一した方法でキャンセルするのが最善です。
方法 1 - アンチ- タイマーによるシェイク処理
効果: ユーザーが同じボタンを複数回クリックした場合連続して、最後のクリックの後、短時間後にリクエストが開始されます
原則: メソッドが呼び出されるたびに、最後にタイマーが生成されます。タイマーの期限が切れると、リクエストはメソッドが繰り返し呼び出された場合、現在のタイマーはキャンセルされ、新しいタイマーが作成され、タイマーが終了した後にリクエストが送信されます。作業中にサードパーティのカプセル化されたツールの機能を使用できます。たとえば、lodash の
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>
Preview
ケース 2- アンチインターフェイスメソッドの -shake
ボタン間で呼び出されるメソッドは同じです メソッドに対して手ぶれ補正処理を行うことは可能ですが、処理自体がメソッドを一度カプセル化するため、前のメソッドの戻り値。変更するには、前のメソッドでさらに処理を行う必要があります。より複雑です。<!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>Preview
(a) 概要 リクエスト メソッドを直接処理し、API を通じて繰り返しリクエストをキャンセルします。 ajax ライブラリのメソッド
ネイティブ ajax キャンセル リクエスト
オブジェクト インスタンス<pre class="brush:js;toolbar:false;"><!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></pre>
Preview
## の 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>
Preview
(c) コードステップ 1 - キャンセルaxios リクエスト インターセプタを介してリクエストを複製します。
via<!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>
Preview
<!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>
Preview
通过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 がリクエストの繰り返しをどのように防ぐかについて説明します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。