[TOC]
# 函數節流
函數節流(throttle) 保證持續執行方法分隔為每 Xms 執行一次。
比如,乘坐地鐵,過閘機時,每個人進入后 3 秒后門關閉,等待下一個人進入。
## 應用場景:
1. DOM 元素的拖拽功能實現(mousemove)
2. 射擊游戲的 mousedown/keydown 事件(單位時間只能發射一顆子彈),技能 CD
3. 計算鼠標移動的距離(mousemove)
4. Canvas 模擬畫板功能(mousemove)
5. 搜索聯想功能(keyup)
6. 滾動加載,加載更多或滾到底部監聽
7. 就像每 200ms 監測滾動位置來觸發 css 動畫。
```
function throttle(fn, delay) {
var prevTime = Date.now();
return function() {
var curTime = Date.now();
if (curTime - prevTime > delay) {
fn.apply(this, arguments);
prevTime = curTime;
}
};
}
// 使用
var throtteScroll = throttle(function() {
console.log('throtte');
}, 1000);
window.onscroll = throtteScroll;
```
# 函數防抖
函數防抖(debounce)就是指觸發事件后在 n 秒內函數只能執行一次,如果在 n 秒內又觸發了事件,則會重新計算函數執行時間。
簡單的說,當一個動作連續觸發,則只執行最后一次。
比如,坐公交,司機需要等最后一個人進入才能關門。每次進入一個人,司機就會多等待幾秒再關門。
## Debounce Implementations(實現)
2009 年在 John Hann 的文章中第一次看到 debounce 的實現方法。
在那之后不久,Ben Alman 寫了一個 jQuery 插件 (現在不在維護),一年以后 Jeremy Ashkenas 把此方法添加到 underscore.js 中,不久又被添加到 lodash 中。
這三種實現方法內部不同,但是接口幾乎一致。
有段時間 underscore 采用了 Lodash 的實現方法,后來兩個庫的實現開始分道揚鑣。
Lodash 在`_.debounce`和`_.throttle`中添加了許多特性。immediate 標示替代了 leading 和 trailing。你可以二選一或者都選,默認情況下,只有 trailing 是開啟的。
```
function debounce(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
// 使用
window.onscroll = debounce(function() {
console.log('debounce');
}, 1000);
```
## 應用場景:
1. 搜索框搜索輸入。只需用戶最后一次輸入完,再發送請求
2. 手機號、郵箱驗證輸入檢測
3. 窗口大小 Resize。只需窗口調整完成后,計算窗口大小。防止重復渲染。
# 異同比較
相同點:
都可以通過使用 setTimeout 實現。
目的都是,降低回調執行頻率,節省計算資源。
不同點:
函數防抖,在一段連續操作結束后,處理回調,利用 clearTimeout 和 setTimeout 實現。函數節流,在一段連續操作中,每一段時間只執行一次,頻率較高的事件中使用來提高性能。
函數防抖關注一定時間連續觸發,只在最后執行一次,而函數節流側重于一段時間內只執行一次。
# 源碼學習
可以訪問這個 [在線演示](http://demo.nimius.net/debounce_throttle/) 來查看 Debounce、Throttle 和默認情況的事件監聽效果。
建議先看下 lodash 里 debounce 和 throttle 的用法:
[debounce](https://www.lodashjs.com/docs/latest#_debouncefunc-wait0-options)
[throttle](https://www.lodashjs.com/docs/latest#_throttlefunc-wait0-options)
# 參考
See[David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)for details over the differences between[`_.debounce`](https://www.lodashjs.com/docs/latest#debounce)and[`_.throttle`](https://www.lodashjs.com/docs/latest#throttle)
[underscore throttle 與 debounce 節流](https://zhuanlan.zhihu.com/p/26054718)
- 修仙之路
- 基礎原理篇
- JS和Node.js事件環機制剖析
- 一圖理解原型鏈
- 手寫篇
- 基礎手寫
- 手寫實現 Promise A+ 類庫
- 手寫 CommonJS
- 手寫 Express 框架
- 手寫 React Router 4.0
- 手寫虛擬 DOM 和 DOM-Diff
- 手寫 Webpack 實現
- 手寫一個 MVVM 類庫
- 手寫一個 Vue-cli 腳手架
- 手寫 JWT 類庫
- 手寫 Mobx 類庫
- 手寫前端性能和錯誤監控框架
- 手寫 Vue 路由
- 手寫 Vuex 實現
- 手寫 redux 狀態容器
- 手寫 throttle 和 debounce
- Node 高級
- Mongodb
- 安全測試篇
- CSRF原理實現
- XSS原理實現
- 九種跨域方法全解析
- 編寫單元測試
- 爬蟲篇
- 使用puppeteer破解滑動驗證碼
- 工程篇
- 使用AST語法樹手工轉譯ES6代碼
- 編寫自己的webpack插件
- 實戰篇
- webpack4.0 實戰
- Canvas+Websocket 實現彈幕
- canvas 動效
- SVG 動效
- CSS3 實現 Apple Watch 中的呼吸燈效果
- CSS3 實現動態氣泡屏保效果
- 算法篇
- 基礎知識
- 服務器端
- 分布式架構中的冪等性
- TCP/UDP
- Docker
- V8
- 動畫篇
- 貝塞爾曲線
- requestAnimationFrame
- 框架篇
- 隨記