/**
* * @param fn {Function} 实际要执行的函数 * @param delay {Number} 延迟时间,也就是阈值,单位是毫秒(ms) * * @return {Function} 返回一个“去弹跳”了的函数 */ function debounce(fn, delay) { // 定时器,用来 setTimeout let timer; // 返回一个函数,这个函数会在一个时间区间结束后的 delay 毫秒时执行 fn 函数 return function() { // 保存函数调用时的上下文和参数,传递给 fn let context = this; let args = arguments; // 每次这个返回的函数被调用,就清除定时器,以保证不执行 fn clearTimeout(timer); // 当返回的函数被最后一次调用后(也就是用户中止了某个连续的操做), // 再过 delay 毫秒就执行 fn timer = setTimeout(function() { fn.apply(context, args); }, delay); }; }
其实思路很简单,debounce 返回了一个闭包,这个闭包依然会被连续频繁地调用,可是在闭包内部,却限制了原始函数 fn 的执行,强制 fn 只在连续操做中止后只执行一次。debounce 的使用方式以下:git
$(document).on( 'mouvemove', debounce(function(e) { // 代码 }, 250) );
throttle 的概念理解起来更容易,就是固定函数执行的速率,即所谓的“节流”。正常状况下,mousemove 的监听函数可能会每 20ms(假设)执行一次,若是设置 200ms 的“节流”,那么它就会每 200ms 执行一次。好比在 1s 的时间段内,正常的监听函数可能会执行 50(1000/20) 次,“节流” 200ms 后则会执行 5(1000/200) 次。github
与 debounce 相似,咱们这个 throttle 也接收两个参数,一个实际要执行的函数 fn,一个执行间隔阈值 threshhold。一样的,throttle 的更完整实现能够参看 underscore 的 _.throttle
。闭包
/**
* * @param fn {Function} 实际要执行的函数 * @param delay {Number} 执行间隔,单位是毫秒(ms) * * @return {Function} 返回一个“节流”函数 */ function throttle(fn, threshhold) { // 记录上次执行的时间 let last; // 定时器 let timer; // 默认间隔为 250ms threshhold || (threshhold = 250); // 返回的函数,每过 threshhold 毫秒就执行一次 fn 函数 return function() { // 保存函数调用时的上下文和参数,传递给 fn let context = this; let args = arguments; let now = +new Date(); // 若是距离上次执行 fn 函数的时间小于 threshhold,那么就放弃 // 执行 fn,并从新计时 if (last && now < last + threshhold) { clearTimeout(timer); // 保证在当前时间区间结束后,再执行一次 fn timer = setTimeout(function() { last = now; fn.apply(context, args); }, threshhold); // 在时间区间的最开始和到达指定间隔的时候执行一次 fn } else { last = now; fn.apply(context, args); } }; }
原理也不复杂,相比 debounce,无非是多了一个时间间隔的判断,其余的逻辑基本一致。throttle 的使用方式以下:app
$(document).on( 'mouvemove', throttle(function(e) { // 代码 }, 250) );