防止重複發送 Ajax 請求

要考慮並理解 success, complete, error, timeout 這些事件的區別,並註冊正確的事件,一旦失誤,功能將再也不可用;
不可避免地比普通流程要要多註冊一個 complete 事件;
恢復狀態的代碼很容易和不相干的代碼混合在一塊兒;

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

A. 獨佔型提交
只容許同時存在一次提交操做,而且直到本次提交完成才能進行下一次提交。html

module.submit = function() {
  if (this.promise_.state() === 'pending') {
    return
  }
  return this.promise_ = $.post('/api/save')
}

B. 貪婪型提交
無限制的提交,可是以最後一次操做爲準;亦即須要儘快給出最後一次操做的反饋,而前面的操做結果並不重要。git

module.submit = function() {
  if (this.promise_.state() === 'pending') {
    this.promise_.abort()
  }
  // todo
}

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

C. 節制型提交
不管提交如何頻繁,任意兩次有效提交的間隔時間一定會大於或等於某一時間間隔;即以必定頻率提交。api

module.submit = throttle(150, function() {
  // todo
})

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

D. 懶惰型提交
任意兩次提交的間隔時間,必須大於一個指定時間,纔會促成有效提交;即不給休息不幹活。promise

module.submit = debounce(150, function() {
  // todo
})

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

============
更多記憶中的例子

方式 C 和 方式 D 有時更加通用,好比這些狀況:
遊戲中你撿到一把威力強大的高速武器,爲了防止你的子彈在屏幕上打成一條直線,能夠 throttle 來控制頻率;
在彈幕型遊戲裏,爲了防止你把射擊鍵夾住來進行無腦遊戲,能夠用 debounce 來控制頻率;
在編譯任務裏,守護進程監視了某一文件夾裏全部的文件(如任一文件的改變均可以觸發從新編譯,一次執行就須要2秒),但某種操做可以瞬間形成大量文件改變(如 git checkout),這時一個簡單的 debounce 可使編譯任務只執行一次。

而方式 C 甚至能夠和方式 B 組合使用,好比自動完成組件(Google 首頁的搜索就是):
當用戶快速輸入文本時(特別是打字能手),能夠 throttle keypress 事件處理函數,以指定時間間隔來提取文本域的值,而後當即進行新的查詢;
當新的查詢須要發送,但上一個查詢還沒返回結果時,能夠 abort 未完成的查詢,並當即發送新查詢;服務器

參考資料:http://www.qdfuns.com/notes/17755/d62094bd9972ddd957ca4da671a48ff0.html編輯器

相關文章
相關標籤/搜索