防抖函数
什么是防抖函数
我们用一幅图来理解他的过程
- 当事件触发的时候,相应的函数并不会立即触发,而是等待一定的时间
- 当事件密集触发的时候,函数的触发也会频繁的推迟
- 只有等待了一段时间也没有事件触发,才会真正执行响应函数
什么是节流函数
同样,用一幅图来理解他的过程
- 当事件触发时,会执行这个响应函数
- 如果这个事件函数频繁触发,节流函数会按照一定的频率来执行函数
- 不管在这个中间有多少次触发事件,执行函数总会按照一定的频率执行
防抖函数的简单实现
基本实现
function debounce(fn,delay){
// 定义一个定时器变量,保存上一次的定时器
let timer = null
// 真正的执行函数
return function _debounce(){
//如果上一次定时器存在,取消上一次的定时器
if(timer) clearTimeout(timer)
// 延时执行事件函数
timer = setTimeout(()=>{
//外部传入的真正要执行的函数
fn()
},delay)
}
}
优化一:优化参数和this的指向
function debounce(fn,delay){
// 定义一个定时器变量,保存上一次的定时器
let timer = null
// 真正的执行函数
return function _debounce(...args){
//如果上一次定时器存在,取消上一次的定时器
if(timer) clearTimeout(timer)
// 延时执行事件函数
timer = setTimeout(()=>{
//外部传入的真正要执行的函数
fn.apply(this,args)
},delay)
}
}
优化二:立即执行
function debounce(fn,delay,immediate =false){
// 定义一个定时器变量,保存上一次的定时器
let timer = null
//
let isInvoke = false
// 真正的执行函数
return function _debounce(...args){
//如果上一次定时器存在,取消上一次的定时器
if(timer) clearTimeout(timer)
//判断是否立即执行
if(immediate && !isInvoke){
fn.apply(this,args)
isInvoke = true
}else{
// 延时执行事件函数
timer = setTimeout(()=>{
//外部传入的真正要执行的函数
fn.apply(this,args)
isInvoke = false
},delay)
}
}
}
优化三:取消功能
function debounce(fn,delay,immediate =false){
// 定义一个定时器变量,保存上一次的定时器
let timer = null
//
let isInvoke = false
// 真正的执行函数
const _debounce = function(...args){
//如果上一次定时器存在,取消上一次的定时器
if(timer) clearTimeout(timer)
//判断是否立即执行
if(immediate && !isInvoke){
fn.apply(this,args)
isInvoke = true
}else{
// 延时执行事件函数
timer = setTimeout(()=>{
//外部传入的真正要执行的函数
fn.apply(this,args)
isInvoke = false
},delay)
}
}
//封装取消功能
_debounce.cancel =function(){
if(timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
节流函数的简单实现
基本实现
function throttle(fn,interval){
//记录上一次开始的时间
let lastTime = 0
//事件触发时,真正执行的函数
const _throttle = function(){
//获取当前事件的触发时间
const nowTime = new Date().getTime()
//使用当前触发时间和之前的时间间隔以及上一次开始的时间,计算出还剩余多长时间去触发函数
const remainTime = interval - (nowTime - lastTime)
if(remainTime <= 0){
//真正的触发函数
fn()
//保留上次的触发事件
lastTime = nowTime
}
}
return _throttle
}
优化一:决定第一次触不触发
/**
@param leading 用于控制第一次触不触发
*/
function throttle(fn,interval,options={leading:true}){
//记录上一次开始的时间
let lastTime = 0
const { leading } = options
//事件触发时,真正执行的函数
const _throttle = function(){
//获取当前事件的触发时间
const nowTime = new Date().getTime()
if(!lastTime && !leading) lastTime = nowTime
//使用当前触发时间和之前的时间间隔以及上一次开始的时间,计算出还剩余多长时间去触发函数
const remainTime = interval - (nowTime - lastTime)
if(remainTime <= 0){
//真正的触发函数
fn()
//保留上次的触发事件
lastTime = nowTime
}
}
return _throttle
}
优化二:超过频率的最后一次执不执行
/**
* @param leading 用于控制第一次触不触发
* @param trailing 控制超过频率的最后一次执不执行
*/
function throttle(fn,interval,options={leading:true,trailing: false}){
//记录上一次开始的时间
let lastTime = 0
const { leading ,trailing } = options
let timer = null
//事件触发时,真正执行的函数
const _throttle = function(){
//获取当前事件的触发时间
const nowTime = new Date().getTime()
if(!lastTime && !leading) lastTime = nowTime
//使用当前触发时间和之前的时间间隔以及上一次开始的时间,计算出还剩余多长时间去触发函数
const remainTime = interval - (nowTime - lastTime)
if(remainTime <= 0){
if(timer){
clearTimeout(timer)
timer = null
}
//真正的触发函数
fn()
//保留上次的触发事件
lastTime = nowTime
return
}
if(trailing && !timer){
timer = setTimeout(()=>{
timer = null
lastTime = !leading ? 0 : new Date().getTime()
fn()
},remainTime)
}
return _throttle
}
优化三:优化参数和this的指向
function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing } = options
let lastTime = 0
let timer = null
// 2.事件触发时, 真正执行的函数
const _throttle = function(...args) {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
// 2.3.真正触发函数
fn.apply(this, args)
// 2.4.保留上次触发的时间
lastTime = nowTime
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
lastTime = !leading ? 0: new Date().getTime()
fn.apply(this, args)
}, remainTime)
}
}
_throttle.cancel = function() {
if(timer) clearTimeout(timer)
timer = null
lastTime = 0
}
return _throttle
}
优化四:取消功能
function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing } = options
let lastTime = 0
let timer = null
// 2.事件触发时, 真正执行的函数
const _throttle = function(...args) {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
// 2.3.真正触发函数
fn.apply(this, args)
// 2.4.保留上次触发的时间
lastTime = nowTime
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
lastTime = !leading ? 0: new Date().getTime()
fn.apply(this, args)
}, remainTime)
}
}
_throttle.cancel = function() {
if(timer) clearTimeout(timer)
timer = null
lastTime = 0
}
return _throttle
}