防抖与节流
防抖意义:防抖是为了避免无效操作,也就是说当前操作是否有效,取决于在一定时间内是否有下一次操作,如果有,则覆盖上一次操作。
使用场景:
例如关键词搜索,input 框为了提高客户体验,一般都是绑定 oninput 而非 onchange,这种情况下,
- 如果客户 100 ms 内连续输入多个字符,就会触发多次 api 请求,很浪费服务端资源。
- 响应很快的情况下,搜索结果多次连续渲染会造成视觉抖动,客户体验也会很差。
- 还有一个是算法本身,如果输入一个连续且关联性较高的内容,相对来说会搜索到比较满意的结果,反之就会搜索到一些不相关的信息。
所以我们需要做一个延时功能,在客户一定时间内没有动作的时候才触发有效搜索。
节流意义:节流是为了阻止无效操作,也就是说当前操作正在执行,在执行完毕之前,后续的操作都是无效的,所以说防抖讲究延时性,而节流讲究及时性。
使用场景:
例如表单提交,提交的一瞬间就应该锁定表单,禁止重复提交,直到客户端接收到响应后解除锁定。
另一个场景例如鼠标滚动加载,我们的习惯是一次性滚动一个比较大的范围,但是我们希望只有第一次执行,从而保证既能及时加载数据又不至于太浪费资源。
所以我们需要做一个及时但是节流的功能,在首次动作完成之前,后续的动作都是无效的。
实现:
1 /* 这个函数返回一个动作,并记录动作的次数 */ 2 function getHandle(markup) { 3 let count = 0; 4 return () => console.log(markup, ++count); 5 } 6 7 /* 防抖 */ 8 function debounce(delay, handle) { 9 let timer = null; 10 return function (record) { 11 console.log(record); 12 timer && clearTimeout(timer); 13 timer = setTimeout(handle, delay); 14 }; 15 } 16 const handle = debounce(100, getHandle("debounce done")); 17 handle("debounce 1"); 18 handle("debounce 2"); 19 handle("debounce 3"); 20 21 /* 节流 */ 22 function throttle(delay, handle) { 23 let flag = false; 24 return function (record) { 25 console.log(record); 26 if (flag) return; 27 flag = true; 28 const result = handle(); 29 if (result instanceof Promise) { 30 result.then(() => (flag = false)); 31 } else { 32 setTimeout(() => (flag = false), delay); 33 } 34 }; 35 } 36 const handle1 = throttle(100, getHandle("throttle done")); 37 handle1("throttle 1"); 38 handle1("throttle 2"); 39 handle1("throttle 3"); 40 41 /* 这个函数返回一个异步动作,并记录动作的次数 */ 42 function getAsyncHandle(markup) { 43 let count = 0; 44 return () => 45 new Promise((res, rej) => { 46 console.log(markup, ++count); 47 setTimeout(() => res(), 100); 48 }); 49 } 50 51 const handle2 = throttle(100, getAsyncHandle("async throttle done")); 52 handle2("async throttle 1"); 53 handle2("async throttle 2"); 54 handle2("async throttle 3");
测试结果:
这个结果说明测试通过了,我们把它写成一个模块,以便在项目的任何地方使用。
模块化:
1 /* 防抖 */ 2 function debounce(delay, handle) { 3 let timer = null; 4 return function () { 5 timer && clearTimeout(timer); 6 timer = setTimeout(handle, delay); 7 }; 8 } 9 10 /* 节流 */ 11 function throttle(delay, handle) { 12 let flag = false; 13 return function () { 14 if (flag) return; 15 flag = true; 16 const result = handle(); 17 if (result instanceof Promise) { 18 result.then(() => (flag = false)); 19 } else { 20 setTimeout(() => (flag = false), delay); 21 } 22 }; 23 } 24 25 export { debounce, throttle };
--- THE END ---