防抖与节流

防抖意义:防抖是为了避免无效操作,也就是说当前操作是否有效,取决于在一定时间内是否有下一次操作,如果有,则覆盖上一次操作。

使用场景:

例如关键词搜索,input 框为了提高客户体验,一般都是绑定 oninput 而非 onchange,这种情况下,

  1. 如果客户 100 ms 内连续输入多个字符,就会触发多次 api 请求,很浪费服务端资源。
  2. 响应很快的情况下,搜索结果多次连续渲染会造成视觉抖动,客户体验也会很差。
  3. 还有一个是算法本身,如果输入一个连续且关联性较高的内容,相对来说会搜索到比较满意的结果,反之就会搜索到一些不相关的信息。

所以我们需要做一个延时功能,在客户一定时间内没有动作的时候才触发有效搜索。

节流意义:节流是为了阻止无效操作,也就是说当前操作正在执行,在执行完毕之前,后续的操作都是无效的,所以说防抖讲究延时性,而节流讲究及时性。

使用场景:

例如表单提交,提交的一瞬间就应该锁定表单,禁止重复提交,直到客户端接收到响应后解除锁定。

另一个场景例如鼠标滚动加载,我们的习惯是一次性滚动一个比较大的范围,但是我们希望只有第一次执行,从而保证既能及时加载数据又不至于太浪费资源。

所以我们需要做一个及时但是节流的功能,在首次动作完成之前,后续的动作都是无效的。

实现:

 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 ---

posted @ 2022-11-03 19:31  万物有序  阅读(203)  评论(0编辑  收藏  举报