函数防抖与函数节流
为什么会有函数防抖
我们现在有一个input
框,需要实现一个类似搜索引擎的功能,当输入文字时进行模糊查询业务。
<input type="text" id="debounce">
<script type="text/javascript">
document.getElementById('debounce').oninput = function() {
console.log('发送模糊查询请求');
}
</script>
下图可见,当我们输出中文北京
时,每个输入字符都会发送请求。如果不是特别需要,并且后端要求没有那么高的情况下这么做对于服务器的压力无疑是非常大的。
这里我们可以使用函数防抖来进行优化,思想大概就是将不停地请求抖动转化成一个按压式的弹簧,弹簧被按压时不会发起请求,只有弹起时才会发生请求。
<input type="text" id="debounce">
<script type="text/javascript">
var processor = {
timeoutId: null,
performProcessing: function() {
console.log('发送模糊查询请求');
},
process: function() {
var that = this;
clearTimeout(that.timeoutId);
that .timeoutId = setTimeout(function() {
that.performProcessing();
}, 300)
}
};
document.getElementById('debounce').oninput = function() {
processor.process();
}
</script>
使用了新的代码后只有当用户停止输入时才会发送请求,服务器压力会减少很多。
为什么会有函数节流
有的朋友可能会对函数节流和函数抖动的概念有所混淆。函数抖动是反复执行的任务,在一个限定范围时间内只调用一次;而函数节流是反复执行的任务,降低调用的频率。
我们现在有一个可滚动的div,每当滚动时我们将div的宽度加10个像素。
<div id="throttle">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eum, alias reprehenderit! Dolore voluptatum atque praesentium eius soluta vel ducimus nesciunt eligendi provident ea adipisci voluptatibus, culpa repellat ut alias amet.
</div>
<script type="text/javascript">
document.getElementById('throttle').onscroll = function(event) {
var w= parseInt(event.target.offsetWidth);
event.target.style.width = (w + 10) + "px";
console.log('我被滚动了');
}
</script>
可以发现只要我们轻轻滚动一次滚轮,可能触发10次增加宽度。
这个时候节流函数就派上了用场。
<div id="throttle">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eum, alias reprehenderit! Dolore voluptatum atque praesentium eius soluta vel ducimus nesciunt eligendi provident ea adipisci voluptatibus, culpa repellat ut alias amet.</div>
<script type="text/javascript">
// 时间戳方式
var throttle = function(func, delay) {
var prev = Date.now();
return function() {
var context = this;
var args = arguments;
var curr = Date.now();
if (delay - (curr - prev) <= 0) {
func.apply(context, args);
prev = Date.now();
}
}
}
// 定时器方式
var throttle = function(func, delay) {
var timer = null;
return function() {
var context = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function() {
func.apply(context, args);
timer = null;
}, delay);
}
}
}
// 定时器和时间戳组合方式
var throttle = function(func, delay) {
var timer = null;
var startTime = Date.now();
return function() {
var currTime = Date.now();
var context = this;
var args = arguments;
var remaining = delay - (currTime - startTime);
clearTimeout(timer);
if (remaining <= 0) {
func.apply(context, args);
startTime = Date.now();
} else {
timer = setTimeout(function() {
func.apply(context, args);
startTime = Date.now();
}, remaining);
}
}
}
document.getElementById('throttle').onscroll = throttle(function(event) {
var w= parseInt(event.target.offsetWidth);
event.target.style.width = (w + 10) + "px";
console.log('我被滚动了');
}, 1000);
</script>
可以发现使用了节流函数后,滚动的频率减少了很多。