一文学会JavaScript如何手写防抖节流
一、什么是防抖和节流
1、防抖(Debounce):
定义:在事件触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
应用场景:输入框实时搜索、窗口调整等。
实现思路:通过定时器实现,如果在规定时间内再次触发事件,则清除上一次的定时器并重新设置。
2、节流(Throttle):
定义:对于连续多次触发的事件,每隔一段固定时间执行一次。
应用场景:鼠标点击、监听滚动事件、input输入等。
实现思路:通过记录上次执行的时间戳,判断当前时间与上次时间的差值是否大于设定的间隔时间,如果是则执行函数。
二、防抖的实现
基本版
function debounce(fn, delay) { let timer; return function() { clearTimeout(timer); timer = setTimeout(fn, delay); } }
闭包优化版
function debounce(fn, delay) { let timer; return function() { const context = this; const args = arguments; clearTimeout(timer); timer = setTimeout(function() { fn.apply(context, args); }, delay); } }
立即执行增强版
function debounce(fn, delay) { let timer; let isImmediatelyInvoked = false; return function() { const context = this; const args = arguments; if (!isImmediatelyInvoked) { fn.apply(context, args); isImmediatelyInvoked = true; } clearTimeout(timer); timer = setTimeout(function() { isImmediatelyInvoked = false; }, delay); } }
三、节流的实现
时间戳版
function throttle(fn, wait) { let preTime = 0; return function() { const context = this; const args = arguments; const now = +new Date(); if (now preTime > wait) { fn.apply(context, args); preTime = now; } } }
定时器版
function throttle(fn, wait) { let timeout; return function() { const context = this; const args = arguments; if (!timeout) { timeout = setTimeout(function() { fn.apply(context, args); timeout = null; }, wait); } } }
组合版
function throttle(fn, wait) { let preTime = 0; let timeout; return function() { const context = this; const args = arguments; const now = +new Date(); const remaining = wait (now preTime); if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } preTime = now; fn.apply(context, args); } else if (!timeout) { timeout = setTimeout(function() { preTime = +new Date(); timeout = null; fn.apply(context, args); }, remaining); } } }
四、自定义版节流
在组合版的基础上,设置一个options对象参数,根据传的值判断要哪一种效果,规定:
leading
: false表示禁用第一次执行。
trailing
: false表示禁用停止触发的回调。
function throttle(fn, wait, options = {}) { let timeout; let preTime = 0; const leading = options.leading === false; const trailing = "trailing" in options ? options.trailing : true; return function() { const context = this; const args = arguments; const now = +new Date(); if (!leading && now < preTime) return; // 禁用第一次执行 const remaining = wait (now preTime); if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } preTime = now; fn.apply(context, args); if (!trailing) return; // 禁用停止触发的回调 } else if (!timeout) { timeout = setTimeout(function() { preTime = +new Date(); timeout = null; fn.apply(context, args); }, remaining); } } }
五、相关问题与解答栏目
1. 什么时候使用防抖和节流?它们有什么区别?
解答:防抖和节流都是用于限制高频事件触发的性能优化手段,防抖是将多次事件触发合并为最后一次触发,适用于输入框搜索、窗口调整等场景;而节流是每隔一段时间只执行一次事件,适用于滚动事件、鼠标移动等场景,具体选择哪种方式取决于实际需求。
如何在项目中应用防抖和节流?
解答:可以通过将防抖或节流函数封装后绑定到相应的事件上来实现,对于输入框的实时搜索功能,可以使用防抖函数来减少搜索请求的次数;对于滚动加载更多数据的功能,可以使用节流函数来控制数据加载的频率,具体实现可以参考上述代码示例。
各位小伙伴们,我刚刚为大家分享了有关“一文学会JavaScript如何手写防抖节流”的知识,希望对你们有所帮助。如果您还有其他相关问题需要解决,欢迎随时提出哦!