浏览器默认事件监听间隔: 4 - 6 ms, 对于某些场景不必要这么快速: 滚动,轮播, 点击 等
防抖: 高频操作只识别一次,(第一次或最后一次)
截流:对于高频操作 按照规定间隔出发,减少4 - 6 ms频率触发次数
防抖之最后一次 & 第一次
原始代码:
var oBtn = document.getElementById('btn')
oBtn.onclick = function () {
console.log('test')
}
思路分析:
1. 需要: 原始function
2. 触发click事件后进行控制, 需要: 原始function , 间隔时间, 开始/结束执行限制 , 这些控制本身需要一个function, 这个function : myDebounce(func, time, status)
3. myDebounce() 参数判断+默认值处理: func 是否为函数, time 是否为数字, 是否为undefined,time 是否为boolean, status是否为boolean。 如果有问题 赋予默认值
4. 返回一个代理函数(内置定时器)
5. 执行定时器前清空定时器,抛弃之前的定时器, 只执行最后一个
6. this 指向 和 参数传递, let self = this && ...args
7. 第一次触发执行, true ( 计时器 是否为空- 是否触发逻辑,传递参数是否为true-执行第一次出发逻辑)
var oBtn = document.getElementById('btn')
// handle 执行的函数, wait 等待时间, immediate: 1/0 - 开始/结束执行
function myDebounce (handle, wait, immediate){
if(typeof handle !== 'function') throw new Error ('handle must be a function') // 3. 判断参数类型 + 默认值处理
if(typeof wait === 'undefined' ) wait = 300
if(typeof wait === 'boolean' ) {
immediate = wait
wait = 300
}
// 惰性执行函数
let timer = null
return function proxy(...args) { // 2. 既然会执行那就返回一个代理函数来执行 , 6.接受未知参数 ...args
let self = this // 6. 储存this
clearTimeout(timer) // 5. 检查: 清楚之前的setTimeout, 只执行最后一个
init =immediate && !timer
timer = setTimeout(()=>{ // 4. 这个函数 里 有一个定时器, 在wait后执行 // note:定时器的返回值是一个整数(定时器编号)
timer = null
!immediate ? handle.call('end',self, ...args) : null // 6. 绑定this,使用参数
},wait)
init ? handle.call('start', self, ...args) : null
}
}
function btnClick(ev){
console.log(this, ev)
}
oBtn.onclick = myDebounce(btnClick, 300, true) // 1. 这样会直接调用mydebounce
截流:自定义时间内让事件触发
原始代码:
// css
body {
height: 1500px;
}
// js
function scrollFn(){
console.log('gg')
}
window.onscroll = scrollFn
思路分析:
1. 调用截流函数, 传入调用函数 和 间隔时间 => 返回一个代理函数
2. 参数判断 ? 确定传入了正确参数, 没有就加默认值
3. 逻辑判断: 预定时间差 - (当前时间 - 上次执行时间) => 大于0 则 高频 ,小于0 则 触发
4. 高频操作限制: a. 使用定时器 使 handle 在 指定时间执行 , b. “也就是说 高频触发的事件都会有一个定时器来延迟 c. 那么: 有定时器 = 已有一次高频触发” d. 如果有高频出发了就不执行 e. if( !timer) {setTimeout(()=>{},200)}
5. 清空定时器 和 timer 变量: 为了下一次出设定定时器触发高频事件
6. 特殊情况: browser 和 自定义触发事件 时间点重合 那么定时器不会开启,
clear Timeout (timer)
timer =null
// throttle
function throttle(handle, time){
if(typeof handle !== 'function') throw new Error('handle must be a function')
if(typeof time === 'undefined') wait = 400
let previous = new Date
return function proxy(...args){
let self = this
let now = new Date()
let difference = time - (now - previous)
let timer = null
if(difference <= 0){
clearTimeout(timer)
timer = null
handle.call(self, ...args)
previous = new Date()
}else if(!timer) {
timer = setTimeout(()=>{
clearTimeout(timer)
timer = null
handle.call(self, ...args)
previous = new Date()
},difference)
}
}
}
function scrollFn(){
console.log('gg')
}
// window.onscroll = scrollFn
window.onscroll = throttle(scrollFn, 300)