防抖和节流
1. 防抖
1.1 一图胜千言
- 当用户停止操作后的一段时间内才会执行一次,如果用户一直操作,就不会执行
- 适用于输入框的输入事件,滚动事件,窗口大小改变事件等
1.2 简易版防抖函数实现
js
const debounce = (fn, delay) => {
// 闭包
let timer = null;
// 真正执行的函数
const _debounce = function () {
// 取消上一次定时器
if(timer) clearTimeout(timer)
// 延迟执行
timer = setTimeout(() => {
fn()
}, delay)
}
return _debounce()
}
1.3 防抖增加this执行和参数传递
js
function debounce(fn, delay) {
let timer = null;
return function (...args) {
if(timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args)
},delay)
}
}
1.4 防抖增加立即执行
js
function debounce(fn, delay, immediate = false) {
let timer = null;
let isInvoke = false;// 这个东西是否之前执行过
return function (...args) {
if(timer) clearTimeout(timer);
// 判断是否需要立即执行
if(immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
}else {
timer = setTimeout(() => {
fn.apply(this, args)
isInvoke = false
},delay)
}
}
}
1.5 防抖增加取消功能
js
function debounce(fn, delay, immediate = false) {
let timer = null;
let isInvoke = false;// 这个东西是否之前执行过
function _debounce(...args) {
if(timer) clearTimeout(timer);
// 判断是否需要立即执行
if(immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
}else {
timer = setTimeout(() => {
fn.apply(this, args)
isInvoke = false
},delay)
}
}
_debounce.cancel = function () {
if(timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
1.6 防抖增加返回值
js
function debounce(fn, delay, immediate = false, callBack) {
let timer = null;
let isInvoke = false;// 这个东西是否之前执行过
function _debounce(...args) {
return new Promise((resolve,reject) => {
if(timer) clearTimeout(timer);
// 判断是否需要立即执行
if(immediate && !isInvoke) {
const result = fn.apply(this, args)
if(callBack) callBack(result)
resolve(result)
isInvoke = true
}else {
timer = setTimeout(() => {
const result = fn.apply(this, args)
if(callBack) callBack(result)
resolve(result)
isInvoke = false
},delay)
}
})
}
_debounce.cancel = function () {
if(timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
2. 节流
2.1 一图胜千言
- 当用户一直操作时,每隔一段时间执行一次
- 监听滚动事件,用户频繁点击按钮, 飞机大战游戏等
2.2 简易版防抖函数实现
js
function throttle (fn, interval) {
let lastTime = 0;
const _throttle = function () {
const nowTime = new Date().getTime()
const remainTime = interval - (nowTime - lastTime)
if(remainTime <= 0){
fn()
lastTime = nowTime
}
}
return _throttle
}
2.3 leading: 实现防抖函数第一次不执行(可选)
js
function throttle (fn, interval, options = { leading: true, trailing: false}) {
// 1. 记录上一次开始的时间
const { leading , trailing } = options
let lastTime = 0;
const _throttle = function () {
const nowTime = new Date().getTime()
// 是第一次执行并且leading不需要第一次执行
if(!lastTime && !leading) lastTime = nowTime
const remainTime = interval - (nowTime - lastTime)
if(remainTime <= 0){
fn()
lastTime = nowTime
}
}
return _throttle
}
2.4 trading: 输入突然停止,最后一次也触发
js
function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing } = options
let lastTime = 0
let timer = null
// 2.事件触发时, 真正执行的函数
const _throttle = function() {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
// 2.3.真正触发函数
fn()
// 2.4.保留上次触发的时间
lastTime = nowTime
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
lastTime = !leading ? 0: new Date().getTime()
fn()
}, remainTime)
}
}
return _throttle
}
2.5 this参数
js
function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing } = options
let lastTime = 0
let timer = null
// 2.事件触发时, 真正执行的函数
const _throttle = function(...args) {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
// 2.3.真正触发函数
fn.apply(this, args)
// 2.4.保留上次触发的时间
lastTime = nowTime
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
lastTime = !leading ? 0: new Date().getTime()
fn.apply(this, args)
}, remainTime)
}
}
return _throttle
}
2.6 取消功能
js
function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing } = options
let lastTime = 0
let timer = null
// 2.事件触发时, 真正执行的函数
const _throttle = function(...args) {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
// 2.3.真正触发函数
fn.apply(this, args)
// 2.4.保留上次触发的时间
lastTime = nowTime
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
lastTime = !leading ? 0: new Date().getTime()
fn.apply(this, args)
}, remainTime)
}
}
_throttle.cancel = function() {
if(timer) clearTimeout(timer)
timer = null
lastTime = 0
}
return _throttle
}
2.7 函数返回值
js
function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing, resultCallback } = options
let lastTime = 0
let timer = null
// 2.事件触发时, 真正执行的函数
const _throttle = function(...args) {
return new Promise((resolve, reject) => {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
// 2.3.真正触发函数
const result = fn.apply(this, args)
if (resultCallback) resultCallback(result)
resolve(result)
// 2.4.保留上次触发的时间
lastTime = nowTime
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
lastTime = !leading ? 0: new Date().getTime()
const result = fn.apply(this, args)
if (resultCallback) resultCallback(result)
resolve(result)
}, remainTime)
}
})
}
_throttle.cancel = function() {
if(timer) clearTimeout(timer)
timer = null
lastTime = 0
}
return _throttle
}