防抖和节流
一、 为什么需要防抖和节流
在编写业务的过程中,通常会给元素绑定很多事件。执行事件的过程中,如果存在“高频”触发的场景,多次且连续的触发,可能会造成不必要的性能问题,影响体验。从优化的角度触发,此时需要对事件进行需要进行防抖和节流。
如以下场景:
- 点击按钮提交表单(多次点击)
- 页面滚动
- 输入框:输入模糊搜索
- ...
二、什么是函数防抖
在事件触发的时候,开始计时,如果在规定时间内,事件再次被触发,则清空上一次计时,然后重新开始计时,保证在规定时间内事件没有再次被触发,再去执行这个事件。
简单的说就是在规定时间内多次被触发,仅仅只会执行一次(可以控制开始就执行,还是最后一次再执行)。如多次点击提交表单按钮,在一定时间内只执行一次
/**
* 防抖
* @param {fnc} function
* @param {wait} number 延迟多久执行
* @param {immediate} boolean 是否第一次触发就立即执行
* @return {function}
*/
function debounce(func, wait, immediate) {
if (typeof func !== 'function') throw new TypeError('func must be an function!')
if (typeof wait === 'undefined') wait = 500
if (typeof wait === 'boolean') {
immediate = wait
wait = 500
}
if (typeof immediate !== 'boolean') immediate = false
// 设定定时器返回值标识
let timer = null;
return function proxy(...params) {
let self = this
// immediate为ture并且不存在定时器才算第一次执行
let now = immediate && !timer
clearTimeout(timer);
timer = setTimeout(function () {
timer = null;
if (!immediate) {
func.call(self, ...params)
}
}, wait);
// 第一次触发就立即执行
if (now) {
func.call(self, ...params)
}
};
}
// 使用
function handle(e) {
// 在点击的时候要处理的业务
console.log(this, e)
}
document.getElementById('submit').addEventListener('click', debounce(handle, true))
三、什么是函数节流
在某一次高频触发下,不是只识别一次,而是按照设定的间隔时间(自己规定的频率),每到达这个频率都会触发一次;假设规定频率是500MS,我们操作了1min,触发的次数就是(1 * 60 * 1000) / 500,可以理解为是减少执行频率。使用场景如:多数为监听页面元素滚动
/**
* 节流
* @param {fnc} function
* @param {wait} number 触发事件的时间间隔
* @return {function}
*/
function throttle(func, wait) {
if (typeof func !== 'function') {
throw new TypeError('func must be an function!')
}
if (typeof wait === 'undefined') wait = 500
let timer = null,
previous = 0 // 记录上一次操作的时间
return function proxy(...params) {
let self = this,
now = new Date(), //当前这次触发操作的时间
remaining = wait - (now - previous)
if (remaining <= 0) {
// 两次间隔时间超过wait了,直接执行即可
clearTimeout(timer)
timer = null
previous = now
func.call(self, ...params)
} else if (!timer) {
// 两次触发的间隔时间没有超过wait,则设置定时器
// 让其等待remaining这么久之后执行一次「前提:没有设置过定时器」
timer = setTimeout(function () {
clearTimeout(timer)
timer = null
previous = new Date()
func.call(self, ...params)
}, remaining)
}
}
}
// 使用
function handle() {
console.log('throttle')
}
window.onscroll = throttle(handle, 500)