js防抖和节流实现
概念
1. 防抖(debounce):触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间
举例:就好像在百度搜索时,每次输入之后都有联想词弹出,这个控制联想词的方法就不可能是输入框内容一改变就触发的,他一定是当你结束输入一段时间之后才会触发。
2.节流(throttle):高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执行频率
举例:预定一个函数只有在大于等于执行周期时才执行,周期内调用不执行。就好像你在淘宝抢购某一件限量热卖商品时,你不断点刷新点购买,可是总有一段时间你点上是没有效果,这里就用到了节流,就是怕点的太快导致系统出现bug。
应用场景:提交表单、高频监听事件
3. 区别:防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。
4. 防抖应用场景
- 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
- 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
- 文本编辑器实时保存,当无任何更改操作一秒后进行保存
5. 节流应用场景
scroll
事件,每隔一秒计算一次位置信息等- 浏览器播放事件,每个一秒计算一次进度信息等
- input 框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 (也可做防抖)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Title</title> </head> <body> <div> <h3>防抖</h3> <div> <input type="text" id="debounce" /> </div> <h3>节流</h3> <div> <input type="text" id="throttle" /> </div> <h3>不加节流和防抖</h3> <div> <input type="text" id="unDebounce" /> </div> </div> <script> // 防抖:一段时间内只能执行一次,如果触发了新事件,则重新开始计算时间 // 节流:每隔一段时间执行一次,如果两次事件开始时间大于限定时间间隔,则可以再次执行 // 二者都使用闭包实现,来记录起始时间,delay 为时间间隔, function throttle(fn, delay) { let begin = 0; let timer = null; // 这个 timer 是为了避免最后一次事件执行没达到就节流时间导致的没执行而兜底 return function () { clearTimeout(timer); // 每次调用记录一个 flag 表示该次方法执行是否成功调用 let flag = false; let cur = new Date().getTime(); // 如果下次执行的时候已经超过限定时间间隔,则执行方法 if (cur - begin > delay) { fn.apply(this, arguments); begin = cur; flag = true; } // 如果本次方法没执行, if (!flag) { timer = setTimeout(() => { fn.apply(this, arguments); }, delay); } }; } function debounce(fn, delay) { let timer = null; let fistClick = false; return function () { if (!fistClick) { fistClick = true; fn.apply(this, arguments); } if (timer) { clearTimeout(timer); } timer = setTimeout(() => { fn.apply(this, arguments); }, delay); }; } let throttleElem = document.getElementById("throttle"); let debounceElem = document.getElementById("debounce"); let unDebounceElem = document.getElementById("unDebounce"); throttleElem.onkeyup = throttle(function (e) { console.log("throttle"); console.log(e.target.value); }, 2000); debounceElem.onkeyup = debounce(function (e) { console.log("debounce"); console.log(e.target.value); }, 2000); unDebounceElem.onkeyup = function (e) { console.log("unDebounce"); console.log(e.target.value); }; </script> </body> </html>
参考:https://github.com/shfshanyue/Daily-Question/issues/3