JS函数节流和函数防抖
栏目: JavaScript · 发布时间: 7年前
内容简介:防抖(如果一个事件被频繁触发多次,并且触发的时间间隔过短,则防抖函数可以使得对应的事件处理函数只执行最后触发的一次。 函数防抖可以把多个顺序的调用合并成一次。如果一个事件被频繁触发多次,节流函数可以按照固定频率去执行对应的事件处理方法。 函数节流保证一个事件一定时间内只执行一次。
-
在浏览器中某些计算和处理要比其他的昂贵很多。例如
DOM操作比起非DOM交互需要更多的内存和CPU占用时间。连续尝试进行过多的DOM操作可能会导致浏览器挂起,甚至崩溃; -
例如当调整浏览器大小的时候,
resize事件会连续触发;如果在resize事件处理程序内部尝试进行DOM操作,其高频率的更改可能会让浏览器崩溃; - 为了绕开上面的问题,需要对该类函数进行节流;
2.什么是函数防抖和函数节流
防抖(
debounce
)和节流(
throttle
)都是用来控制某个函数在一定时间内执行多少次的技巧,两者相似而又不同。
背后的基本思想是 某些代码不可以在没有间断的情况下连续重复执行。
2.1 函数防抖 ( debounce
)
如果一个事件被频繁触发多次,并且触发的时间间隔过短,则防抖函数可以使得对应的事件处理函数只执行最后触发的一次。 函数防抖可以把多个顺序的调用合并成一次。
2.2 函数节流 ( throttle
)
如果一个事件被频繁触发多次,节流函数可以按照固定频率去执行对应的事件处理方法。 函数节流保证一个事件一定时间内只执行一次。
3.应用场景
| 类型 | 场景 |
|---|---|
| 函数防抖 |
1. 手机号、邮箱输入检测 2. 搜索框搜索输入(只需最后一次输入完后,再放松Ajax请求) 3. 窗口大小 resize
(只需窗口调整完成后,计算窗口大小,防止重复渲染) 4.滚动事件 scroll
(只需执行触发的最后一次滚动事件的处理程序) 5. 文本输入的验证(连续输入文字后发送 AJAX 请求进行验证,(停止输入后)验证一次就好 |
| 函数节流 |
1. DOM
元素的拖拽功能实现( mousemove
) 2. 射击游戏的 mousedown
/ keydown
事件(单位时间只能发射一颗子弹) 3. 计算鼠标移动的距离( mousemove
) 4. 搜索联想( keyup
) 5. 滚动事件 scroll
,(只要页面滚动就会间隔一段时间判断一次) |
4.如何实现
4.1 函数防抖实现
function debounce(fn, delay, scope) {
let timer = null;
// 返回函数对debounce作用域形成闭包
return function () {
// setTimeout()中用到函数环境总是window,故需要当前环境的副本;
let context = scope || this, args = arguments;
// 如果事件被触发,清除timer并重新开始计时
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
}
}
复制代码
- 代码解读
- 第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码;
- 当第二次调用该函数时,它会清除前一次的定时器并设置另一个;
- 如果前一个定时器已经执行过了,这个操作就没有任何意义;
- 然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器;
-
目的是
只有在执行函数的请求停止了
delay时间之后才执行 。
4.2 函数节流实现
4.2.1 利用时间戳简单实现
function throttle(fn, threshold, scope) {
let timer;
let prev = Date.now();
return function () {
let context = scope || this, args = arguments;
let now = Date.now();
if (now - prev > threshold) {
prev = now;
fn.apply(context, args);
}
}
}
复制代码
4.2.2 利用定时器简单实现
function throttle2(fn, threshold, scope) {
let timer;
return function () {
let context = scope || this, args = arguments;
if (!timer) {
timer = setTimeout(function () {
fn.apply(context, args);
}, threshold);
}
}
}
复制代码
5 举例( scroll
事件)
CSS代码
.wrap {
width: 200px;
height: 330px;
margin: 50px;
margin-top: 200px;
position: relative;
float: left;
background-color: yellow;
}
.header{
width: 100%;
height: 30px;
background-color: #a8d4f4;
text-align: center;
line-height: 30px;
}
.container {
background-color: pink;
box-sizing: content-box;
width: 200px;
height: 300px;
overflow: scroll;
position: relative;
}
.content {
width: 140px;
height: 800px;
margin: auto;
background-color: #14ffb2;
}
复制代码
HTML代码
<div class="wrap">
<div class="header">滚动事件:普通</div>
<div class="container">
<div class="content"></div>
</div>
</div>
<div class="wrap">
<div class="header">滚动事件:<strong>加了函数防抖</strong></div>
<div class="container">
<div class="content"></div>
</div>
</div>
<div class="wrap">
<div class="header">滚动事件:<strong>加了函数节流</strong></div>
<div class="container">
<div class="content"></div>
</div>
</div>
复制代码
JS代码
let els = document.getElementsByClassName('container');
let count1 = 0,count2 = 0,count3 = 0;
const THRESHOLD = 200;
els[0].addEventListener('scroll', function handle() {
console.log('普通滚动事件!count1=', ++count1);
});
els[1].addEventListener('scroll', debounce(function handle() {
console.log('执行滚动事件!(函数防抖) count2=', ++count2);
}, THRESHOLD));
els[2].addEventListener('scroll', throttle(function handle() {
console.log(Date.now(),', 执行滚动事件!(函数节流) count3=', ++count3);
}, THRESHOLD));
复制代码
// 函数防抖
function debounce(fn, delay, scope) {
let timer = null;
let count = 1;
return function () {
let context = scope || this,
args = arguments;
clearTimeout(timer);
console.log(Date.now(), ", 触发第", count++, "次滚动事件!");
timer = setTimeout(function () {
fn.apply(context, args);
console.log(Date.now(), ", 可见只有当高频事件停止,最后一次事件触发的超时调用才能在delay时间后执行!");
}, delay);
}
}
复制代码
// 函数节流
function throttle(fn, threshold, scope) {
let timer;
let prev = Date.now();
return function () {
let context = scope || this, args = arguments;
let now = Date.now();
if (now - prev > threshold) {
prev = now;
fn.apply(context, args);
}
}
}
复制代码
以上所述就是小编给大家介绍的《JS函数节流和函数防抖》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。