一、函数节流

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);

通过对比可以看到,在输入很快的情况下,只使用函数节流的效果响应不是很及时。