防抖
防抖:
页面中的按钮没有做过处理,频繁点击会触发很多次请求,造成不必要的资源浪费,所以我们需要进行防抖处理
我们假设,只要500ms (规定的高频率触发规则)内触发两次及以上,我们就识别为频繁触发,则最后把需要做的事情只做一次
防抖基础版
// 获取按钮元素
const submit = document.querySelector('#submit');
// 按钮触发后执行的方法
const func = function func() {
console.log('按钮出发了');
}
let timer = null;
submit.onclick = function () {
// 清除上一次设置的定时器
clearTimeout(timer)
// 再重新设置一个新的定时器来监听:500ms 内是否有触发第二次
// 有: 则把之前设置的定时器清除掉,再从新设置一个即可
// 没有: 到时间后把想要执行的方法执行即可
timer = setTimeout(() => {
func()
},500)
}
项目中为了统一维护和管理,在之后类似的情形或者其他功能按钮也需要做类似处理,我们需要进行封装
防抖升级版
// 触发后需要执行的函数
const func = function func() {
console.log('按钮出发了');
}
// 统一清除定时器
const clearTimer = function clearTimer(timer) {
if (timer)clearTimeout(timer)
return null;
}
/**
* 防抖函数
* @param {*} func 执行函数
* @param {*} wait 等待时间
* @returns
*/
const myDebounce = function myDebounce(func, wait) {
if (typeof func !== 'function') throw new TypeError('func must be function')
wait = +wait; // 将wait等待时间转换为数字
// 如果不是数字,赋值为默认值500ms
if(isNaN(wait)) wait = 500
let timer = null;
// 如果点击按钮,传入了一些参数 params ,需要接收参数
return function operate(...params) {
clearTimer(timer)
timer = setTimeout(() => {
// 定时器中的this -> window, 所以需要通过call来修改this指向
func.call(this,...params)
},wait)
}
}
// 调用
myDebounce(func,500)
防抖尊享版
const myDebounce = function myDebounce(func, wait, immediate) {
// init params
if (typeof func !== 'function') throw new TypeError('func must be function')
if (typeof wait === 'boolean') {
immediate = wait;
wait = undefined
}
if (typeof immediate !== 'boolean') immediate = false
wait = +wait;
if (isNaN(wait)) wait = 500;
let timer = null;
return function operate(...params) {
// 开始边界,第一次进来,定时器为空,immediate 为 true
// 之后触发频率内再进来,定时器timer 就不是为空了
let now = !timer && immediate
// 清除定时器触发频率内之前的定时器
clearTimer(timer)
timer = setTimeout(() => {
// 结束边界触发
if (!immediate) func.call(this, ...params)
// 最后一次触发时,定时器到时间了,函数执行,把本次定时器给清除
clearTimer(timer)
}, wait)
// 开始边界触发
if(now) func.call(this,...params)
}
}
节流
场景
鼠标在浏览器中滚动,触发滚动事件. window.onscoll 有一个自己默认的触发频率:浏览器的最快反应时间 [ 谷歌是: 5ms -- 7ms ]
window.onscroll = function func () {
console.log('鼠标滚动');
}
假设鼠标滚动浏览器触发频率是5ms ,当开始滚动,第一个5ms ,设置一个定时器,等待 495ms 之后,开始执行 func 假若在此期间,例如10ms ...及以后又触发了,此时如果存在一个定时器等待执行,则啥都不处理即可 到了495ms 之后,把func 执行,如果此时滚动还在继续,我们还需要在设置定时器,再间隔等待时间(wait)去执行func !
假设等待时间 wait 为 500ms
当前时间 (-) 减去 上一次触发 func 的时间 等于(=)间隔时间差
- 时间差< 500ms
- 有定时器不需要处理
- 没有定时器,设置定时器去等待
- 时间差> 500ms 立即执行 func
节流函数
注意: 当两次触发的时间间隔小于等待的时间,需要看定时器存在不存在(很重要)
- 定时器不存在,我们才设置定时器,定时器等待的时间是
remaining(不是wait) - 存在,不做处理
const clearTimer = function clearTimer(timer) {
if (timer) clearTimeout(timer);
return null;
}
const mythrottle = function mythrottle(func, wait) {
if (typeof func !== 'function') throw new TypeError('func must be function')
wait = +wait // 转成数字
if (isNaN(wait)) wait = 500;
let timer = null, // 定时器
previous = 0;// 记录上一次执行
return function operate(...params) {
// 时间差
let now = + new Date(); // 当前时间
// 两次触发的时间间隔超过设定的频率,则立即执行函数
let remaining = wait - (now - previous); // 剩余时间
if (remaining < 0) {
func.call(this, ...params)
previous = + new Date();
clearTimer(timer) // 函数返回 null,在之后还需要判断定时器存在不,不存在设置定时器重新监听
} else if ( !timer) {
// 时间间隔不足设定的频率间隔,而且还未设置等待的定时器,则设置定时器等待执行函数即可
timer = setTimeout(() => {
func.call(this, ...params)
previous = +new Date();
clearTimer(timer);
}, remaining) // 一定是剩余时间
}
clearTimer(timer)
}
}