目录
函数节流
函数防抖
函数节流和防抖
+ 两种处理 重复高频触发 事件的方式节流
+ 在 单位时间 内只能 触发一次 => 开关 思想
防 抖
+ 在 单位时间 内, 如果重复出现同样的事件, 那么把前一次干掉
重复高频触发事件 : 额外浪费浏览器性能 ( 触发了 11 次 事件 )
函数节流
+ 在固定范围内只执行一次事件+ 用在一个异步的时候, 并且两个异步的事情不可以同时触发+ 在一个固定时间段内, 多次触发事件的时候, 只执行第一次
函数节流之后只 触发了 4 次 事件 , 节约了浏览器 7 次 的操作性能 ( 7次 请求 , 7次 渲染页面 )
/**
*
* 函数节流
* @param {*} fn
* @param {number} [wait=600]
* @return {*}
*/
function throttle(fn, wait = 600) {
// 上一次执行时间
let prevTime = 0
// 定时器
let timer = null
return function (ev) {
// 当前时间
let nowTime = Date.now()
// 计算当前是否达到了设置的执行时长
let diffTime = wait - (nowTime - prevTime)
if(diffTime <= 0) { // 到达设置的时长
// 让上一次执行的时间设置为当前执行的时间
prevTime = nowTime
// 清除定时器
clearTimeout(timer)
timer = null
// 执行回调函数, 注意 this 指向
fn.call(this, ev)
} else if(!timer) {
timer = setTimeout(() => {
// 清除定时器
clearTimeout(timer)
timer = null
// 执行回调函数, 注意 this 指向
fn.call(this, ev)
}, wait);
}
}
}
函数防抖
( 应用较多 )
瀑布流 或者 下拉加载 等等...都经常会使用
+ 在 固定时间 内 , 只触发事件 一次+ 每一次触发事件的时候 , 都会 从新计时 开始+ 例子: 我规定 600ms 你不输入内容 , 那么再开始 触发事件=> 第一次输入内容 h , 延迟 600ms 以后 再 触发=> 假设当我在 300ms 的时候 , 输入了内容 e=> 那么 h 内容的 事件 就 不触发 了=> 而是从输入 e 开始 , 再次延时 600ms 后触发事件
函数防抖之后只 触发了 1 次 事件 , 节约了浏览器 10 次 的操作性能 ( 10次 请求 , 10次 渲染页面 )
淘宝 : 节省了浏览器的性能( 运用了 函数防抖 )
/**
* @param Function fn 回调函数 防抖
* @param int wait 等待时间 默认600ms
* @param bool now true/false true点击即执行, 但只执行一次
* @param {*} fn
* @param {number} [wait=600]
* @param {boolean} [now=true]
* @return {*}
*/
function debounce(fn, wait = 600, now = true) {
// 标识 定时器
let timer = null
return function (ev) {
// 判断它是否开始执行还是最后执行
let start = now && !timer
// 清除定时器
clearTimeout(timer)
timer = setTimeout(() => {
timer = null
// 让 this 指向到原来的位置上
!now ? fn.call(this, ev) : null
}, wait);
// 立即执行
start ? fn.call(this, ev) : null
}
}
/**
* 函数防抖 是n秒后延迟执行, 多用于页面 scroll 滚动, 窗口 resize, 防止按钮重复点击
* @param {*} fn 是我们需要包装的事件回调
* @param {*} delay 是每次推迟执行的等待时间
* @returns
*/
const debounce = (fn, delay = 1000) => {
let timer = null; // 定时器
// 将 debounce 处理结果当做函数返回
return function () {
// 保留调用时的 this 上下文
let context = this;
// 保留调用时传入的参数
let args = arguments;
// 每次事件被触发时, 都去清除之前的旧的定时器
if (timer) {
clearTimeout(timer);
}
// 设立新的定时器
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
};
项目中 所用 防抖 函数 及 应用 :
/**
* @param {Function} func
* @param {Number} wait
* @param {Boolean} immediate
* @param {*}
*/
export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result;
const later = function () {
// 根据上一次触发时间间隔
const last = +new Date() - timestamp;
// 上一次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
// 如果设定为 immediate===true, 因为开始边界已经调用过了,此处无需调用
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
return function (...args) {
context = this;
timestamp = +new Date();
const callNow = immediate && !timeout;
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
};
}
应用 :
点击按钮