本文共 3135 字,大约阅读时间需要 10 分钟。
在实际开发中,频繁触发DOM操作或资源加载可能导致UI卡顿甚至浏览器崩溃。以下场景经常引发问题:
针对这些事件,有两种常见的解决方案:debounce 和 throttle。
debounce 的核心思想是:在指定的空闲时间内,多次触发同一事件只执行一次。类似于弹簧的状态,只有在手松开后才会恢复原状。
简单实现:
var debounce = function(idle, action) { var last = null; return function() { var ctx = this; var args = arguments; clearTimeout(last); last = setTimeout(function() { action.apply(ctx, args); }, idle); };}; throttle 的目标是限制事件处理的执行频率。每隔指定时间执行一次相关操作,类似于水流的滴落。
简单实现:
var throttle = function(delay, action) { var last = 0; return function() { var curr = +new Date(); if (curr - last > delay) { action.apply(this, arguments); last = curr; } };}; _.throttle = function(func, wait, options) { var context, args, result; var timeout = null; var previous = 0; if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { var now = _.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; };}; 精彩之处:
remaining <= 0 用于检测是否满足空闲时间。remaining > wait 用于处理时间异常(如系统时间修改)。_.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; var later = function() { var last = _.now() - timestamp; if (last < wait && last > 0) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } }; return function() { context = this; args = arguments; timestamp = _.now(); var callNow = immediate && !timeout; if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; };}; 精彩之处:
setTimeout 来确保在空闲时间内只执行一次函数。immediate 参数控制是否在首次调用时立即执行函数。debounce 和 throttle 都通过减少事件处理的执行频率来提升性能,但核心机制有明显差异:
选择时需结合具体需求,结合各JS库的实现进行深入理解。