这里写目录标题
函数防抖:debounce
我们在平时开发的时候,会有很多场景会频繁触发事件,比如说搜索框实时发请求, onmousemove, resize, onscroll等等,有些时候,我们并不能或者不想频繁触发事件, 咋办呢?这时候就应该用到函数防抖和函数节流了!
//应用场景,百度搜索框,监控文本框内容变化, 但是他不是时时刻刻监控,我们打完字后会等一下才自动搜索,可以自己取百度搜索体验一下
监控窗口发生变化的函数,如果不用函数防抖,
那么在拖动的过程中会触发很多次,这不是我们想看到了
- 1.不添加函数防抖的window.onresize函数
当你窗口拖动时,会连续触发很多次,输出很多次aaaa。
window.onresize = function () {
console.log("aaaa");
}
- 2.简单封装过后的函数防抖,运行过后发现并没有什么卵用,只不过是延迟了一秒在重复上面的操作,自己试试 体验一下这个思考的过程。然后我们再继续优化
window.onresize = function () {
debounce(function () {
console.log("a");
}, 1000)
}
/**
* 函数防抖
* callback,传入需要运行的函数
* time ,多少时间后运行这个函数
*/
function debounce(callback, time) {
setTimeout(function () {
callback();
}, time)
}
- 3.我们再换一种方式处理,每次调用setTime之前我们把计时器id清除,这个时候就发现 一个粗糙的函数防抖已经做好了,但是这个有个缺点,定义了一个timer污染了全局变量,所以并不是完美的,还需要继续优化
window.onresize = function () {
debounce(function () {
console.log("a");
}, 1000)
}
/**
* 函数防抖
* callback,传入需要运行的函数
* time ,多少时间后运行这个函数
*/
var timer;
function debounce(callback, time) {
clearTimeout(timer)
timer = setTimeout(function () {
callback();
}, time)
}
- 4.继续优化,我们把timer定义在函数内部,利用闭包使变量私有。然后返回一个函数,在外部定义一个变量handle接收返回的函数,再在onresize触发事件中调用这个函数。这个时候你是不是觉得这个函数到这里就差不多了。是差不多了,这个时候已经可以应对绝大多数的情况了,但是还忽略了一点,没有考虑到传递参数的情况
//在函数内部返回一个新的函数叫高阶函数
var handle = debounce(function () {
console.log("a");
}, 1000)
window.onresize = function () {
handle();
}
/**
* debounce函数防抖
* callback,传入需要运行的函数
* time ,多少时间后运行这个函数
*/
function debounce(callback, time) {
var timer;
return function () {
clearTimeout(timer)
timer = setTimeout(function () {
callback();
}, time)
}
}
//debounce函数在这里的作用就是开启一个计时器,专供返回的函数使用,
- 5.传参优化,窗口每一次改变的时候我要输出窗口的值。考虑到多个参数的情况,我们直接借用函数内部的arguments。
var handle = debounce(function (width) {
console.log(width);
}, 1000)
window.onresize = function () {
handle(document.documentElement.clientWidth);
}
/**
* 函数防抖
* callback,传入需要运行的函数
* time ,多少时间后运行这个函数
*/
function debounce(callback, time) {
var timer;
return function () {
clearTimeout(timer) //清除之前的计时
var args = arguments; //保存当前函数参数数组,把参数带到setTimeout里面需要执行的函数。这里也有一点闭包的感觉
timer = setTimeout(function () {
callback.apply(null, args);
//因为参数是个伪数组,而apply传递参数就是用数组传递,所以我们就正好利用这一点
// 让apply帮忙,但是this指向不需要用到,所以我们给个null
}, time)
}
}
利用刚刚写好的函数模拟百度搜索,自己试试哦
function debounce(callback, time) {
var timer;
return function () {
clearTimeout(timer) //清除之前的计时
var args = arguments; //保存当前函数参数数组,把参数带到setTimeout里面需要执行的函数。这里也有一点闭包的感觉
timer = setTimeout(function () {
callback.apply(null, args);
//因为参数是个伪数组,而apply传递参数就是用数组传递,所以我们就正好利用这一点
// ,让apply帮忙,但是this指向不需要用到,所以我们给个null
}, time)
}
}
var inp = document.querySelector("input");
var handle = debounce(function (val) {
console.log("搜索了" + val);
}, 1000)
inp.oninput = function () {
handle(this.value)
}
函数节流 throttle
保证一个时间段内只执行一次,函数节流有俩种做法,第一种是立即执行一次再说,第二种是等时间到了再执行第一次
- 时间到了再执行第一次
/*函数节流 throttle
*
*/
function throttle(callback, time) {
var timer;
return function () {
if (timer) {
return;
} //如果发现当前已经有计时了,啥都不做
var args = arguments; //保存当前函数参数数组,把参数带到setTimeout里面需要执行的函数。这里也有一点闭包的感觉
timer = setTimeout(function () {
callback.apply(null, args);
timer = null; //执行一次后timer必须清空,不然永远不会执行下一次了
}, time)
}
}
var handle = throttle(function () {
console.log("a")
}, 1000);
handle()
handle()
handle()
handle()
handle()
handle()
handle()
handle()
handle()
//连续调用handle函数,在1000毫秒内也只会执行一次。
- 马上触发一次,下一下等一秒,利用时间戳
function throttle(callback, time) {
var t;
return function () {
if (!t || Date.now() - t >= time) {
callback.apply(null, arguments);
t = Date.now()
}
}
}
- 俩种结合,传递第三个参数
function throttle(callback, time,immediately) {
var t;
var timer;
return function () {
if(immediately){
if (!t || Date.now() - t >= time) {
callback.apply(null, arguments);
t = Date.now()
}
}
if(!immediately){
if (timer) {
return;
} //如果发现当前已经有计时了,啥都不做
var args = arguments; //保存当前函数参数数组,把参数带到setTimeout里面需要执行的函数。这里也有一点闭包的感觉
timer = setTimeout(function () {
callback.apply(null, args);
timer = null; //执行一次后timer必须清空,不然永远不会执行下一次了
}, time)
}