函数节流与函数去抖
一、函数节流
1、定义
预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。
函数节流的核心是,让一个函数不要执行得太频繁,减少一些过快的调用来节流。
function throttle(method, delay){
var last = 0;
return function(){
var curr = +new Date();
if(curr - last >= delay){
method.apply(this, arguments);
last = curr;
}
};
}
2、Example
- 未使用函数节流
function test(){
console.log(" do something... ");
}
window.onmousemove = function(){
test();
};
- 使用函数节流
function throttle(method, delay){
var last = 0;
return function(){
var curr = +new Date();
if(curr - last >= delay){
method.apply(this, arguments);
last = curr;
}
};
}
function test(){
console.log("do something...");
}
window.onmousemove = throttle(test, 1000);
二、函数去抖
1、定义
当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作,则将重新计算执行时间。简单的说,函数去抖就是对于一定时间段的连续的函数调用,只让其执行一次。
function debounce(method, delay){
var timer = null;
return function(){
var context = this;
clearTimeout(timer);
timer = setTimeout(function(){
method.apply(context, arguments);
}, delay);
};
}
2、Example
- 未使用函数去抖
var count = 0;
function resize(){
console.log(++count, " do something... ");
}
window.onresize = function(){
resize();
};
- 使用函数去抖
写法一:
function debounce(method, delay){
var context = this,
args = [].splice.call(arguments, 0);
clearTimeout(method.tid);
method.tid = setTimeout(function(){
args.splice(0, 2);
method.apply(context, args);
}, delay);
}
var count = 0;
function resize(params){
console.log(++count, " do something... ", params);
}
window.onresize = function(){
debounce(resize, 500, "params");
}
写法二:
function debounce(method, delay, params){
var timer = null;
return function(){
var context = this,
args = [].splice.call(arguments, 0);
clearTimeout(timer);
timer = setTimeout(function(){
method.apply(context, args.concat(params));
}, delay);
};
}
var count = 0;
function resize(event, params){
console.log(++count, " do something... ", params);
}
window.onresize = debounce(resize, 500, ["params"]);
三、区别
函数节流和函数去抖的核心其实就是限制某一个方法被频繁触发,而一个方法之所以会被频繁触发,大多数情况下是因为DOM事件的监听回调,而这也是函数节流和函数去抖多数情况下的应用场景。
- 差异
throttle
:相等的时间间隔内执行函数
debounce
:在一定的时间间隔t内若再次触发事件,则重新计时,直到事件停止触发t时间后才执行函数。
四、综合样例
通过结合使用函数去抖和函数节流实现一个自动完成的例子:
- HTML
<div>
<input type="text" id="searchInput" placeholder="请输入搜索内容">
<button id="search">搜索</button>
<ul id="list">
<li>111</li>
<li>11111</li>
<li>1111111</li>
<li>111111111</li>
<li>11111111111</li>
</ul>
</div>
- 通用部分JS
var n = 0;
var input = document.querySelector("#searchInput");
function search(e){
console.log(++n, " search... ");
var i = 0,
li = null,
value = input.value,
list = document.querySelector("#list"),
children = list.children;
if(value){
list.style.display = "block";
for(; i < children.length; i++){
li = children[i];
li.style.display = li.textContent.indexOf(value.toUpperCase()) > -1 ? "block" : "none";
}
}else{
list.style.display = "none";
}
}
document.querySelector("#search").addEventListener("click", function(){
search();
}, false);
- 只使用函数去抖
function debounce(method, delay, params){
var tid = null;
return function(){
var context = this,
args = [].splice.call(arguments, 0);
clearTimeout(tid);
tid = setTimeout(function(){
method.apply(context, args.concat(params));
}, delay);
};
}
input.addEventListener("keyup", debounce(search, 200), false);
- 使用函数节流和函数去抖
function debounce(method, delay, duration){
var tid = null,
begin = new Date();
return function(){
var context = this,
current = new Date(),
args = arguments;
clearTimeout(tid);
if(current - begin >= duration){
method.apply(context, args);
begin = current;
}else{
tid = setTimeout(function(){
method.apply(context, args);
}, delay);
}
};
}
input.addEventListener("keyup", debounce(search, 200, 300), false);
通过对比可以看到,在输入很快的情况下,只使用函数节流的效果响应不是很及时。