表單按鈕重複提交,axios重複請求的處理方案

1.自定義指令directive

思路: 點擊以後當前按鈕必定時間內(例如:setTimeout 1000ms)不能夠再次被點擊,至關於節流;
可是若是一個請求1000ms以上尚未返回,那麼再次點擊就會觸發新的請求了。
添加自定義文件 directives.js
import Vue from 'vue'

const preventReClick = Vue.directive('preventReClick', {
  inserted: function(el, binding) {
    el.addEventListener('click', () => {
      if (!el.disabled) {
        el.disabled = true
        setTimeout(() => {
          el.disabled = false
        }, binding.value || 3000) // 傳入綁定值就使用,默認3000毫秒內不可重複觸發
      }
    })
  }
})

export { preventReClick }
複製代碼

在main.js中引用

import preventReClick from './plugins/directives.js' //防屢次點擊,重複提交複製代碼

在按鈕上添加v-preventReClick

// 指定延遲1000ms <el-button size="small" type="primary" @click="handleSave()" v-preventReClick="1000">保 存</el-button> // 默認延遲時間3000 <el-button size="small" type="primary" @click="handleSave()" v-preventReClick>保 存</el-button> 複製代碼

2.請求隊列與axios.CancelToken取消請求

補充知識點——Axios 的 cancel

Axios 的 cancel token API 基於 cancelable promises proposal

可使用 CancelToken.source 工廠方法建立 cancel token,像這樣:javascript

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:html

var CancelToken = axios.CancelToken;
var cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函數接收一個 cancel 函數做爲參數
    cancel = c;
  })
});

// 取消請求
cancel();
複製代碼

Note : 可使用同一個 cancel token 取消多個請求vue


思路:請求中(pending狀態,服務端還未返回結果以前)的接口存儲一個請求隊列,請求返回以後就從隊列中刪除;若是正在請求中,那麼相同請求再次被觸發也不會調用後臺,而是被cancel;
這個只能在前一次請求服務端未返回結果時候阻止繼續請求。
import axios from 'axios'
const pending = [] // 聲明一個數組用於存儲每一個ajax請求的隊列
const cancelToken = axios.CancelToken // 初始化取消請求的構造函數
let arr = [] // 區分是請求仍是響應的頭部

/** * @param {請求體信息} config * @param {直接執行的cancel函數,執行便可取消請求} f */
const removePending = (config, f) => {
  arr = config.url.split(window.g.apiUrl)
  arr = arr[arr.length - 1]
  const flagUrl = arr + '&' + config.method // 每次請求存儲在請求中隊列的元素關鍵值

  // 當前請求存在隊列中
  if (pending.indexOf(flagUrl) !== -1) {
    if (f) {
      f() // 取消請求
    } else {
      pending.splice(pending.indexOf(flagUrl), 1) // 取消函數不存在,則從隊列中刪除該請求
    }
  } else {
    // 當前請求不在隊列中
    if (f) {
      pending.push(flagUrl)
    }
  }
}
// 添加請求攔截器
axios.interceptors.request.use(
  config => {
    if (config.method === 'post') {
      config.cancelToken = new cancelToken(c => {
        removePending(config, c)
      })
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

axios.interceptors.response.use(response => {
  if (response.config.method === 'post') {
    removePending(response.config)
  }
})
複製代碼


3.其餘狀況

做者:長天之雲
連接:https://www.zhihu.com/question/19805411/answer/15465427
來源:知乎


不推薦用外部變量鎖定或修改按鈕狀態的方式,由於那樣比較難:
  • 要考慮並理解 success, complete, error, timeout 這些事件的區別,並註冊正確的事件,一旦失誤,功能將再也不可用;
  • 不可避免地比普通流程要要多註冊一個 complete 事件;
  • 恢復狀態的代碼很容易和不相干的代碼混合在一塊兒;

我推薦用主動查詢狀態的方式(A、B,jQuery 爲例)或工具函數的方式(C、D)來去除重複操做,並提供一些例子做爲參考:java

A. 獨佔型提交

只容許同時存在一次提交操做,而且直到本次提交完成才能進行下一次提交。
module.submit = function() {
  if (this.promise_.state() === 'pending') {
    return
  }
  return this.promise_ = $.post('/api/save')
}
複製代碼

B. 貪婪型提交

無限制的提交,可是以最後一次操做爲準;亦即須要儘快給出最後一次操做的反饋,而前面的操做結果並不重要。
module.submit = function() {
  if (this.promise_.state() === 'pending') {
    this.promise_.abort()
  }
  // todo
}
複製代碼

好比某些應用的條目中,有一些進行相似「喜歡」或「不喜歡」操做的二態按鈕。若是按下後不當即給出反饋,用戶的目光焦點就可能在那個按鈕上停頓許久;若是按下時即時切換按鈕的狀態,再在程序上用 abort 來實現積極的提交,這樣既能提升用戶體驗,還能下降服務器壓力,皆大歡喜。ios

C. 節制型提交

不管提交如何頻繁,任意兩次有效提交的間隔時間一定會大於或等於某一時間間隔;即以必定頻率提交。
module.submit = throttle(150, function() {
  // todo
})
複製代碼

若是客戶發送每隔100毫秒發送過來10次請求,此模塊將只接收其中6個(每一個在時間線上距離爲150毫秒)進行處理。
這也是解決查詢衝突的一種可選手段,好比以知乎草稿舉例,仔細觀察能夠發現:
編輯器的 blur 事件會當即觸發保存;
保存按鈕的 click 事件也會當即觸發保存;
可是存在一種狀況會使這兩個事件在數毫秒內連續發生——當焦點在編輯器內部,而且直接去點擊保存按鈕——這時用 throttle 來處理是可行的。
另外還有一些事件處理會很頻繁地使用 throttle,如: resize、scroll、mousemove。git

D. 懶惰型提交

任意兩次提交的間隔時間,必須大於一個指定時間,纔會促成有效提交;即不給休息不幹活。
module.submit = debounce(150, function() {
  // todo
})
複製代碼

仍是以知乎草稿舉例,當在編輯器內按下 ctrl + s 時,能夠手動保存草稿;若是你連按,程序會表示不理解爲何你要連按,只有等你放棄連按,它纔會繼續。github

相關文章
相關標籤/搜索