目录
测试代码
import debounce from './手写防抖.js';
import throttle from './手写节流.js';
const inputEl = document.querySelector("input");
const cancelBtn = document.querySelector("#cancel");
let onBody = function (event) {
console.log('最新的内容为: ', event, this);
}
// 防抖测试代码 ---------------
let debounceChange = debounce(onBody, 3000);
inputEl.oninput = debounceChange;
cancelBtn.onclick = function () {
debounceChange.cancel()
}
// 节流测试代码 ---------------
let throttleChange = throttle(onBody, 3000, true);
inputEl.oninput = throttleChange;
cancelBtn.onclick = function () {
throttleChange.cancel()
}
防抖(debounce)
需求:使函数延迟X秒后执行,未执行前调用则重置延迟时间。
实现思路:每次触发清楚宏任务中的事件并重新添加定时器执行。
基本功能实现
function debounce1(fn, delay = 0) {
let timer = null;
// 参数验证
try {
if (typeof fn !== 'function') throw new Error('参数一不是一个函数!');
if (typeof delay !== 'number' || delay < 0) throw new Error('参数二不是一个正数!');
} catch (err) {
console.log(err);
}
return function _debounce() {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn()
}, delay);
}
}
添加参数及this指向功能
function debounce2(fn, delay = 0) {
let timer = null;
// 参数验证
try {
if (typeof fn !== 'function') throw new Error('参数一不是一个函数!');
if (typeof delay !== 'number' || delay < 0) throw new Error('参数二不是一个正数!');
} catch (err) {
console.log(err);
}
// 这里的args是事件回调的参数,和定义方法时传递的不冲突
return function _debounce(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args) //改变this指向并把onclick的event传递
}, delay);
}
}
第一次立即执行功能
function debounce3(fn, delay = 0, immediate = false) {
let timer = null;
let isInvoke = false
// 参数验证
try {
if (typeof fn !== 'function') throw new Error('参数一不是一个函数!');
if (typeof delay !== 'number' || delay < 0) throw new Error('参数二不是一个正数!');
if (typeof immediate !== 'boolean') throw new Error('参数三未不是一个布尔值!');
} catch (err) {
console.log(err);
}
return function _debounce(...args) {
if (timer) clearTimeout(timer)
if (!isInvoke && immediate) {
fn.apply(this, args) //改变this指向并把onclick的event传递
isInvoke = true
} else {
timer = setTimeout(() => {
fn.apply(this, args) //改变this指向并把onclick的event传递
isInvoke = false
}, delay);
}
}
}
取消功能
/**
*
* @param {节流方法} fn
* @param {延迟时间} delay
* @param {是否立即执行} immediate
* @returns
*/
export default function debounce(fn, delay = 0, immediate = false) {
let timer = null;
let isInvoke = false
// 参数验证
try {
if (typeof fn !== 'function') throw new Error('参数一不是一个函数!');
if (typeof delay !== 'number' || delay < 0) throw new Error('参数二不是一个正数!');
if (typeof immediate !== 'boolean') throw new Error('参数三未不是一个布尔值!');
} catch (err) {
console.log(err);
}
const _debounce = function (...args) {
if (timer) clearTimeout(timer)
if (!isInvoke && immediate) {
fn.apply(this, args) //改变this指向并把onclick的event传递
isInvoke = true
} else {
timer = setTimeout(() => {
fn.apply(this, args) //改变this指向并把onclick的event传递
isInvoke = false
}, delay);
}
}
// 添加取消函数
_debounce.cancel = () => {
if (timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
节流(throttle)
需求:X秒内只能执行一次
实现思路:
对比调用时间及上次执行时间的差决定是否执行(时间戳)
每次执行设置定时器,X秒后才能再次执行当前函数。(定时器)
基本功能实现
function throttle1(fn, delay = 0) {
let lastTime = 0
// 参数验证
try {
if (typeof fn !== 'function') throw new Error('参数一不是一个函数!');
if (typeof delay !== 'number' || delay < 0) throw new Error('参数二不是一个正数!');
} catch (err) {
console.log(err);
}
const _throttle = function () {
// 当前时间
let nowTime = new Date().getTime();
// 设置间隔时间 - ( 当前时间 - 上一次执行时间 )
const remainTime = delay - (nowTime - lastTime)
if (remainTime <= 0) {
fn()
lastTime = nowTime
}
}
return _throttle
}
增加this执向
function throttle2(fn, delay = 0) {
let lastTime = 0
// 参数验证
try {
if (typeof fn !== 'function') throw new Error('参数一不是一个函数!');
if (typeof delay !== 'number' || delay < 0) throw new Error('参数二不是一个正数!');
} catch (err) {
console.log(err);
}
const _throttle = function (...args) {
// 当前时间
let nowTime = new Date().getTime();
// 设置间隔时间 - ( 当前时间 - 上一次执行时间 )
const remainTime = delay - (nowTime - lastTime)
if (remainTime <= 0) {
fn.apply(this, args)
lastTime = nowTime
}
}
return _throttle
}
最后一次在禁止时间段内是否执行
function throttle3(fn, delay = 0, trailing = false) {
let lastTime = 0
let timer = null
// 参数验证
try {
if (typeof fn !== 'function') throw new Error('参数一不是一个函数!');
if (typeof delay !== 'number' || delay < 0) throw new Error('参数二不是一个正数!');
if (typeof trailing !== 'boolean') throw new Error('参数三不是一个布尔值!');
} catch (err) {
console.log(err);
}
const _throttle = function (...args) {
// 当前时间
let nowTime = new Date().getTime();
// 设置间隔时间 - ( 当前时间 - 上一次执行时间 )
const remainTime = delay - (nowTime - lastTime)
if (remainTime <= 0) {
fn.apply(this, args)
lastTime = nowTime
clearTimeout(timer)
} else {
if (!trailing) return
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args)
lastTime = nowTime
}, remainTime);
}
}
return _throttle
}
添加取消按钮
/**
*
* @param {节流函数} fn
* @param {延迟时间} delay
* @param {最后一次是否执行} trailing
* @returns
*/
function throttle(fn, delay = 0, trailing = false) {
let lastTime = 0
let timer = null
// 参数验证
try {
if (typeof fn !== 'function') throw new Error('参数一不是一个函数!');
if (typeof delay !== 'number' || delay < 0) throw new Error('参数二不是一个正数!');
if (typeof trailing !== 'boolean') throw new Error('参数三不是一个布尔值!');
} catch (err) {
console.log(err);
}
const _throttle = function (...args) {
// 当前时间
let nowTime = new Date().getTime();
// 设置间隔时间 - ( 当前时间 - 上一次执行时间 )
const remainTime = delay - (nowTime - lastTime)
if (remainTime <= 0) {
fn.apply(this, args)
lastTime = nowTime
clearTimeout(timer)
} else {
if (!trailing) return
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args)
lastTime = nowTime
}, remainTime);
}
}
_throttle.cancel = function () {
if (timer) clearTimeout(timer);
timer = null
lastTime = 0
}
return _throttle
}
定时器实现节流
/**
*
* @param {节流函数} fn
* @param {延迟时间} delay
* @param {最后一次是否执行} trailing
* @returns
*/
function throttle(fn, delay = 0, trailing = false) {
let isInvoke = false
let isLastInvoke = false
let timer = null
// 参数验证
try {
if (typeof fn !== 'function') throw new Error('参数一不是一个函数!');
if (typeof delay !== 'number' || delay < 0) throw new Error('参数二不是一个正数!');
if (typeof trailing !== 'boolean') throw new Error('参数三不是一个布尔值!');
} catch (err) {
console.log(err);
}
const _throttle = function (...args) {
let _this = this
function t() {
timer = setTimeout(() => {
if (isLastInvoke) {
isLastInvoke = false
fn.apply(_this, args)
t();
} else {
isInvoke = false
}
}, delay);
}
if (!isInvoke) {
isInvoke = true
fn.apply(this, args)
t();
} else {
if (!trailing) return
isLastInvoke = true
}
}
_throttle.cancel = function () {
if (timer) clearTimeout(timer);
timer = null
isInvoke = false
isLastInvoke = false
}
return _throttle
}