为什么需要防抖和节流?
- 如果频繁的触发一个事件,每次触发都要执行一次函数,资源请求太频繁,会占用较多浏览器资源造成浏览器卡顿,响应速度跟不上触发速度,导致页面加载缓慢。
什么是防抖?
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。简而言之就是指定时间内频繁触发同一事件,只会执行一次函数。
从这示例(非立即执行版防抖)我们可以得到以下结果:
- 如果在1s内没有再次触发点击事件,那么就执行函数
- 如果在1s内再次触发事件,那么当前的计时取消,重新开始计时
这里防抖又分为2种
立即执行版的防抖:触发事件后函数会立即执行,n 秒内再次触发事件不会执行,n秒后再次触发才会再次执行功能函数。
非立即执行版防抖:触发事件后 n 秒后才执行函数,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。类似于王者荣耀的回城机制。
/**
* 可以封装在工具类里面使用 util.js
* @desc 函数防抖---“立即执行版本” 和 “非立即执行版本” 的组合版
* @param func 执行函数
* @param wait 延迟执行时间(毫秒)
* @param immediate---true 表立即执行,false 表非立即执行
let timeout = null;
export const debounce = (func, wait = 500, immediate = false) => {
// 清除定时器
if (timeout !== null) clearTimeout(timeout);
// 立即执行,此类情况一般用不到
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait);
if (callNow) typeof func === 'function' && func();
} else {
// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
timeout = setTimeout(function() {
typeof func === 'function' && func();
}, wait);
}
}
//页面方法里使用
import {debounce} from '@/util'
methods: {
add(){
debounce(()=>{
/*写要干什么*/
},1000,true)
}
}
防抖应用场景
用户在输入框中连续输入一串字符时,可以通过防抖优化,只在输入完后,才执行查询的请求,这样可以有效减少请求次数,节约性能消耗。(当然节流也是可以的。看自己需求)
页面resize事件,常见于需要做页面适配的时候。需要根据最终呈现的页面情况进行dom渲染(这种情形一般是使用防抖,因为只需要判断最后一次的变化情况)
什么是节流?
如果指定时间内高频触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再执行,直至过了这段时间才重新生效。
节流又分为2种
立即执行版的节流(立即执行)
非立即执行版节流(延迟执行)
/**
* @desc 函数防抖---“立即执行版本” 和 “非立即执行版本” 的组合版
* @param func 执行函数
* @param wait 延迟执行时间(毫秒)
* @param immediate---true 表立即执行,false 表非立即执行
export function throttle_merge(func,wait = 500,immediate=false){
let flag = true;
return function(...args){
if(flag == true){
let context = this
flag = false
immediate&& func.apply(context,args)
setTimeout(() => {
!immediate && func.apply(context,args)
flag = true
},wait)
}
}
}
节流应用场景
监听滚动是否触底加载接口分页。每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。
从这示例(立即执行版节流)我们可以得到以下结果:
- 点击事件每1s执行一次。
总结
函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。