1. 程式人生 > >避免Ajax多次傳送重複請求

避免Ajax多次傳送重複請求

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

還是以知乎草稿舉例,當在編輯器內按下 ctrl + s 時,可以手動儲存草稿;如果你連按,程式會表示不理解為什麼你要連按,只有等你放棄連按,它才會繼續。

更多記憶中的例子

方式 C 和 方式 D 有時更加通用,比如這些情況:

  • 遊戲中你撿到一把威力強大的高速武器,為了防止你的子彈在螢幕上打成一條直線,可以 throttle 來控制頻率;
  • 在彈幕型遊戲裡,為了防止你把射擊鍵夾住來進行無腦遊戲,可以用 debounce 來控制頻率;
  • 在編譯任務裡,守護程序監視了某一資料夾裡所有的檔案(如任一檔案的改變都可以觸發重新編譯,一次執行就需要2秒),但某種操作能夠瞬間造成大量檔案改變(如 git checkout),這時一個簡單的 debounce 可以使編譯任務只執行一次。

而方式 C 甚至可以和方式 B 組合使用,比如自動完成元件(Google 首頁的搜尋就是):

  • 當用戶快速輸入文字時(特別是打字能手),可以 throttle keypress 事件處理函式,以指定時間間隔來提取文字域的值,然後立即進行新的查詢;
  • 當新的查詢需要傳送,但上一個查詢還沒返回結果時,可以 abort 未完成的查詢,並立即傳送新查詢;

E. 記憶型

var scrape = memoize(function(url) {
  return $.post('/scraper', { 'url': url })
})

對於同樣的引數,其返回始終結果是恆等的——每次都將返回同一物件。 應用例子有編輯器,如貼上內容時抓取其中的連結資訊,memoize 用以保證同樣的連結不會抓取兩次。

F. 累積型

曾在處理自動完成事件時得到這個函式,發現也可以用在處理連續事件上,它能夠把連續的多次提交合併為一個提交,比如:

var request = makePile(5, function() {
    $.post('/', { list: JSON.stringify([].slice.call(arguments)) })
})

// 連續傳送五次
request({a:1}), request({a:2}), request({a:3}), request({a:4}), request({a:5})
/* post =>
list:[{"a":1},{"a":2},{"a":3},{"a":4},{"a":5}]
*/

樣例實現:

var makePile = function(count, onfilter, onvalue) {
  var values = [], id = function(value) { return value }
  return function(value) {
    values.push((onvalue || id).apply(this, arguments))
    if (values.length === count) {
      onfilter.apply(this, values)
      values = []
    }
  }
}

另一種累積是按時間而不是次數,比如應用在行為統計上,可能在瞬間收集到數十上百類似的行為,這時可以用上面 pile 的結構加上 debounce 來防止大批重複請求(但又不丟失任何統計):

var trackFactory = function(delay, action) {
  var params = [], slice = [].slice
  var touch = debounce(delay, function() {
    if (params.length) {
      action(params)
      params = []
    }
  })
  return function() {
    params.push(slice.call(arguments))
    touch()
  }
}

var track = trackFactory(550, function(params) {
  // send tracking request
})

G. 取樣型

最近重構時聯想到的,一種和上面都不同的去重操作,可以應用在自動載入(timeline)行為控制上:

autoload.listen(feeds, 'next', sample(3, function() {
  this.enable()
}))

如果 sample 是固化的選擇函式(n 選 1),它這實際上會這樣工作:

O-O-X-O-O-X

但「自動載入」的應用可能想要的是(兩次自動,一次手動):

X-X-O-X-X-O

對於這種情況,可以定義作為配置的選擇函式來實現控制:

options { sample: (n) => n % 3 !== 0 }

即每個下一次載入完成之後, 每三次有兩次對下一次載入實行自動載入。