Open Quickeryi opened 7 years ago
debounce意为消抖、throttle意为节流。这是解决函数请求和响应速度不匹配问题的两个方案!
debounce
throttle
// 给window绑定了resize事件,当我们改变窗口大小时就会触发该事件监听,并且调用resizeListener函数 // 需要注意的是:当改变窗口大小时,resize事件会频繁触发,即使只改变几个像素大小,可能触发几百次 // 而 resizeListener 函数逻辑复杂,需要执行的时间较长,所以此时处理函数无法即时响应高频调用,从而造成卡顿甚至于程序崩溃的现象
let resizeListener = () => { // 这里有一段极其复杂的逻辑,还可能涉及到动画 }; window.onresize = () => { resizeListener(); };
- [x] `debounce` & `throttle`使用场景: 一般而言,这两种策略使用在处理 高频率 `DOM` 事件触发上 ## debounce - [x] 运行机制 简单来说,它会将多个触发合并成一个 - [x] 例子 ```txt 有一部电梯,如果电梯里有人进来,则等待15s,如果15s内又有人进来则再次等待15s,直至超过15s没有人进来,则开始运行
[x] 图说 一般而言,debounce的执行有两种策略leading & trailing,下面使用两幅图来说明两种策略的区别
leading
trailing
[x] 实现
// 下面解读一下underscore.js 的源码 /** * 空闲控制 返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行 * * @param {function} func 传入函数 * @param {number} wait 表示时间窗口的间隔 * @param {boolean} immediate 设置为ture时,调用触发于开始边界而不是结束边界 * @return {function} 返回客户调用函数 */ _.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; var later = function() { // 据上一次触发时间间隔 var last = Date.now() - timestamp; // 上次被包装函数被调用时间间隔last小于设定时间间隔wait if (last < wait && last > 0) { timeout = setTimeout(later, wait - last); } else { timeout = null; // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用 if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } }; return function() { context = this; args = arguments; timestamp = Date.now(); var callNow = immediate && !timeout; // 如果延时不存在,重新设定延时 if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; }; };
概念
let resizeListener = () => { // 这里有一段极其复杂的逻辑,还可能涉及到动画 }; window.onresize = () => { resizeListener(); };
[x] 图说 一般而言,
debounce
的执行有两种策略leading
&trailing
,下面使用两幅图来说明两种策略的区别leading
trailing
[x] 实现