1、提出以下一种场景
(1)搜索框搜索条目的时候,每次onkeyup都会触发一次请求,返回xhr文件,一直输入11111,则每次都会请求。
(2)IE中使用onresize事件处理程序的时候,需根据浏览器窗口大小,来对dom进行频繁操作,改事件也会连续触发。
只要是代码是周期性执行的,都应该使用节流。
目的:防止回调函数每一次都执行
定义:
函数防抖是要在每完成等待某个时间后去执行某函数,而是要每间隔某个时间去执行某函数,避免函数的过多执行。
阿里巴巴是防抖(setTimeout隔一段时间去执行某函数)。淘宝是节流(以周期发送关键字)
RXJS里面有防抖和节流的封装。
2、防抖的实现代码
var container=document.getElementById("container");
function getUserAction(){
container.innerHTML =count++;
}
container.onmousemove= debounce(getUserAction,1000);
function debounce(fn,wait){
var timeout;
return function(){
clearTimeout(timeout);
timeout=setTimeout(fn,wait)
}
}
触发多次onmousemove事件,只会执行最后一次setTimeout(),1s后执行getUserAction
继续增强代码,在执行getUserAction()函数时,我们调用debounce 函数,并不知道外面的div容器是container,所以把container转化为this。
而getUserAction()函数里面的this,是window,因为fn最终在setTimeout()函数里面执行
可以用bind或者apply改变this指向
function debounce(fn,wait){
var timeout;
return function(){
clearTimeout(timeout);
console.log(this)
timeout=setTimeout(fn.bind(this),wait)
}
}
输出为
使用apply
function debounce(fn,wait){
var timeout;
return function(){
clearTimeout(timeout);
var that=this;
timeout=setTimeout(function(){
fn.apply(that)
},wait)
}
}
新的需求:开始边界,在鼠标一移入时则加1 ,之后某一周期内执行一次
function debounce(fn,wait,flag){
var timeout;
return function(){
if(flag){
//判断是第一次进来则调用一次fn
var pd=!timeout; //pd为true,则是第一次进来
clearTimeout(timeout)
timeout = setTimeout(fn.bind(this), wait)
console.log(pd);
if(pd){
fn.apply(this)
}
}else {
clearTimeout(timeout);
timeout = setTimeout(fn.bind(this), wait)
}
}
}
这样就实现了在鼠标一进入count立马加1,之后都是无数次触发后,最后一次执行fn
3、节流的实现代码
function throttle(fn,wait){
var previous=0;//参照物
return function(){
var now=new Date();
console.log(now);
var now1=+new Date();
console.log(now1)
if(now-previous>wait){
console.log(this)
fn.apply(this);
previous=now
}
}
}
输出:
如果new Date()前面有加号,会把标准时间转换为时间戳。这里用Date.now()也可以取到时间戳。
用setTimeout也可以实现节流
function throttle(fn,wait) {
var timeout;
return function () {
var that = this;
if (!timeout) {
timeout = setTimeout(function () {
fn.apply(that);
timeout=null;
}, wait)
}
}
}
注意,这里用了timeout=null;而不是clearTimeout(timeout);
clearTimeout()返回的是一个整数,所以进入一次if,执行一次fn,再也不执行。
另外,注意到此处用的是apply,而不是bind,因为apply是时间1s到了立刻执行,而bind是事先绑定(预处理),等需要执行的时候再执行fn
4、防抖和节流的异同
相同点 | 不同点 |
都是为了避免多次重复连续执行某一函数 | 1、防抖:必须在一个周期后去执行事件触发的函数,即连续触发事件,只 在最后一次触发时去执行函数 2、节流:在不断的触发事件,这一段时间内,按一定周期去执行函数 |
throttle-函数节流:一个水龙头在滴水,可能一次性会滴很多滴,但是我们只希望它每隔 500ms 滴一滴水,保持这个频率。即我们希望函数在以一个可以接受的频率重复调用。
debounce-函数防抖:将一个弹簧按下,继续加压,继续按下,只会在最后放手的一瞬反弹。即我们希望函数只会调用一次,即使在这之前反复调用它,最终也只会调用一次而已。