[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
- 框架篇
- 随记