javaScript防抖与节流函数
文章目录
- 一、概念
- 二、防抖的实现
- 1.简单思想
- 2.中等思想
- 3.高等思想
- 三、节流的实现
- 1.第一种写法:非立即执行
- 2.第二种方法:立即执行一次
- 3.最终写法:可选择是否立即执行
一、概念
防抖(debound):前面的所有触发都被取消,最后一次执行在规定时间之后才触发,也就是说:如果快速的触发 只会触发最后一次
节流(throttle):在规定的时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发(固定时间内只会算一次)
防抖:回城
节流:技能cd
二、防抖的实现
1.简单思想
var timer//保存计时器id
function debounce(callback,delay){
clearTimeout(timer)//清除之前的定时
timer = setTimeout(function(){
callback()
},delay)
}
但是这么写有一个坏处,会污染全局变量,所以能不能考虑将变量写在函数里面,利用闭包来实现
2.中等思想
function debounce(callback,delay){
var timer;
return function(){
clearTimeout(timer)//清除之前的计时
timer = setTimeout(function(){
callback()
},delay)
}
}
//使用
var handle = debounce(function(){
console.log(123)
},1000)
window.onresize=function(){
handle()
}
返回的是一个函数,如果重复触发这个函数,由于使用的是同一个timer,且写在函数里面,不会造成全局变量污染,故可以达到重新计时的功能。
但是还有个问题,如果要传参怎么办?
3.高等思想
function debounce(callback,delay){
var timer;
return function(){
clearTimeout(timer)//清除之前的计时
var args=arguments//利用闭包保存参数数组
timer = setTimeout(function(){
callback.apply(this,args)
},delay)
}
}
//使用
var handle = debounce(function(width){
console.log(width)
},1000)
window.onresize=function(){
handle(document.documentElement.clienWidth)
}
三、节流的实现
1.第一种写法:非立即执行
function throttle(fn, delay) {
let timer = null;
return function () {
//如果存在计时器那么直接返回 不做任何处理
if (timer) {
return;
}
//如果不存在计时器,那么开启一个计时器
timer = setTimeout(() => {
//当计时器结束之后执行
fn.apply(this, arguments);
//将计时器清空否则永远不会结束
timer = null;
}, delay);
};
}
2.第二种方法:立即执行一次
function throttle(fn, delay) {
let timer = null;
return function () {
//之前没有计时或者距离上次执行已经超过timer秒
if (!t||Date.now()-t>=timer) {
callback.apply(this,argument)
t =Date.now()
}
//如果不存在计时器,那么开启一个计时器
timer = setTimeout(() => {
//当计时器结束之后执行
fn.apply(this, arguments);
//将计时器清空否则永远不会结束
timer = null;
}, delay);
};
}
3.最终写法:可选择是否立即执行
//节流的最终形态:可选择是否立即触发
function throttle(fn, delay, immediate = true) {
//如果没有传immediate则默认true
if (immediate) {
let t = null
return function () {
if (!t || Date.now() - t > delay) {
//如果当前时间戳不存在或者当前时间戳减去上一次时间戳大于delay
fn.apply(this, arguments) //执行函数
t = Date.now() //得到当前的时间戳
}
}
} else {
//设置一个定时器id
let timer = null
return function () {
//如果timer值不是setTimeout返回的则直接返回不做处理
if (timer) {
return
}
timer =setTimeout(function () {
fn.apply(null, arguments)
timer = null
}, delay)
}
}
}