前言:
为啥要函数防抖和节流呢,因为像onmousemove ,或者按钮等等被用户频繁移动,点击等情况,造成代码一直在执行导致性能降低,所以用函数防抖和节流来限制在一定时间内函数所能执行的次数
举例
结果:一旦触碰到div并移动,就会一直触发,若还会发送情请求,则对性能影响极大。
什么是防抖?短时间内多次触发同一个事件,只执行最后一次,或者只在开始时执行,中间不执行.
(1)简单版
const debounce = (func, wait, ...args) => {
let timeout; //这里使用闭包来保存局部变量=>tip: 闭包保护的变量会一直保存在内存中但又不会 “污染” 全局的变量
return function () {
const self= this;
if (timeout) clearTimeout(timeout);//当规定时间内最后一次触发的时候才会真正的执行,否则会被清除
timeout = setTimeout(() => {
func.apply(self, args)
}, wait);
}
}
content.onmousemove = debounce(count, 1000);
因为函数防抖和节流都不可避免用到闭包,又重新理解了下闭包
function count() {
let arr = [];
console.log('start');
for (var i=1; i<=3; i++) {
console.log('i:'+i); //被保护的变量会一直保存在内存中,直到被释放
arr.push(function () {
console.log('函数内的i:'+i); //返回的函数只有被执行了才会执行,所以f1,f2,f3被执行时,i已经变成了4
return i * i;
});
}
return arr;
}
let results = count();
let f1 = results[0];
let f2 = results[1];
let f3 = results[2];
console.log(f1());
console.log(f2());
console.log(f3());
运行结果:
(2)改进版
在上述简单版中,在一些特定的场合无法使用,比如一点击就需要立即执行的需求中
function debounce(doSomething, wait, isImmediate) {
let timeout;
return function () {
let _this = this,
_arguments = arguments;
clearTimeout(timeout);
if (isImmediate) {
let isTrigger = !timeout;
timeout = setTimeout(function () {
timeout = null; //在函数结束之后释放内存,并可以进行下一次执行
}, wait);
isTrigger && doSomething.apply(_this, _arguments);
} else {
timeout = setTimeout(function () {
doSomething.apply(_this, _arguments);
}, wait);
}
}
}
function go() {
console.log('666666666');
}
let d1 = document.getElementById('d1');
d1.onclick = debounce(go, 500, true);//true为立即执行版,执行第一次点击, false为执行最后一次的版本
关于定时器的思考:上述代码中,timeout 的值一般从1是开始(这里从2开始),number类型,再一次调用为2,一次增加,代表当前是第几个定时器 ,而timeout = null和clearTimeout是不一样的,赋值timeout 为null,只不过是清除了timer这个变量,清除了timer的内存占用,setTimeout还是存在的,清除定时器只能用clearTimeout(timeout)。
节流是连续触发事件的过程中以一定时间间隔执行函数。节流会稀释你的执行频率,比如每间隔1秒钟,只会执行一次函数,无论这1秒钟内触发了多少次事件。
(1)立即执行版
function throttle(doSomething,wait){
let _this,
_arguments,
initTime = 0;
return function(){
let now = +new Date();//将new date()转化为时间戳
_this = this;
_arguments = arguments;
if(now - initTime>wait){
doSomething.apply(_this,_arguments);
initTime = now;
}
}
}
let d2 = document.getElementById('d2');
d2.onclick = throttle(go, 500);
(2)非立即执行版
function throttle(doSomething,wait){
lettimeout;
return function(){
let _this = this;
_arguments = arguments;
if(!timeout){
timeout = setTimeout(function(){
timeout = null;
doSomething.apply(_this,_arguments);
},wait);
};
}
}
函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖靠清除定时器操作,只是在最后一次事件后或第一次才触发一次函数。