防抖:时间响应函数在一段时间之后才执行,如果在这段时间内再次调用,则会重新计算时间,当预定的时间内没有再次调用该函数,则执行响应逻辑。
function debounce(func, wait, immediate = true) {
// 定义一个timeout计时器
let timeout, result;
let debounced = function () {
// 如果每次进入函数的时候timeout有值,说明等待时间还没有过,不执行函数,清空timeout
// 如果没有timeout,则说明过了等待期,可以执行函数
if (timeout) clearTimeout(timeout);
// 默认立即执行方法,延后执行的话,会让人感觉有卡顿
if (immediate) {
let now = !timeout;
if (now) result = func.apply(this, arguments);
// 不论timeout有没有值,都重新给timeout新添加一个定时器
// 等待wait时间后,将timeout设为null,代表可以继续执行此次function
timeout = setTimeout(() => {
timeout = null;
}, wait);
} else {
// 如果不是立即执行此函数,则在等待wait时间后执行方法
timeout = setTimeout(() => {
func.apply(this, arguments);
}, wait);
}
// 函数返回的内容
return result;
}
// 取消防抖操作
debounced.cancel = function () {
clearTimeout(timeout);
timeout = null;
}
return debounced;
}
应用场景:
1、scroll滚动
2、浏览器窗口resize事件
3、搜索框查询
4、按钮提交事件
节流:如果持续触发事件,则每隔一段时间,只执行一次操作
使用时间戳完成节流函数
// 第一次会触发,最后一次不会触发
function throttle1(func, wait) {
let old = 0;
return function () {
let now = +new Date();
if (now - old > wait) {
old = now;
func.apply(this, arguments);
}
}
}
使用定时器完成节流函数
// 第一次不会触发,最后一次会触发
function throttle2(func, wait) {
let timeout;
return function () {
if (!timeout) {
timeout = setTimeout(() => {
func.apply(this, arguments);
timeout = null;
}, wait)
}
}
}
时间戳和定时器结合完成节流函数
该函数接收第三个参数options:
第一次会触发,最后一次不会触发 leading: true, trailing: false 第一次不会触发,最后一次会触发 leading: false, trailing: true 第一次会触发,最后一次也会触发 leading: true, trailing: true
// 第一次会执行,最后一次也会执行
function throttle(func, wait, options = {}) {
let timeout, old = 0;
const { leading = true, trailing = true } = options;
return function () {
let now = +new Date();
// 第一次会执行
if (now - old > wait && leading) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
old = now;
func.apply(this, arguments);
}
// 最后一次会执行
if (!timeout && trailing) {
timeout = setTimeout(() => {
old = +new Date();
func.apply(this, arguments);
timeout = null;
}, wait)
}
}
}
应用场景:
1、DOM元素的拖拽
2、射击游戏
3、计算鼠标移动的距离
4、监听scroll滚动事件