防抖和节流

防抖和节流是高频操作的优化方案,防抖是把连续的高频操作优化为最后一次操作(常用方案略有不同,此处仅介绍思路),节流是将高频操作降频,固定时间内执行一次。

先通过触发浏览器的mousemove事件来介绍一下防抖和节流的实现:

 1 // html
 2 <body>
 3   <div id="content">0</div>
 4 </body>
 5 
 6 // js
 7 function count() {
 8     document.getElementById('content').innerHTML = Math.random().toFixed(6)
 9   }
10 
11   window.onmousemove = count

在不使用防抖的情况下直接给window绑定事件,只要鼠标移动,事件会一直被触发。

1.防抖debounce

可以在事件被触发时不直接执行处理函数,而是设定一个计时器,事件(短时间内)再次被触发就重新开始计时,直到超过一定间隔后才执行函数。

 1 function debounce(func, wait) {
 2   let timeout
 3   return function () {
 4     if (timeout) {
 5       clearTimeout(timeout)
 6     }
 7     timeout = setTimeout(func, wait)
 8   }
 9 }
10 window.onmousemove = debounce(count, 1000)

查看完整版:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4   <meta charset="UTF-8">
 5   <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6   <title>Debounce</title>
 7   <style>
 8     *{
 9       margin: 0;
10       padding: 0;
11       border: 0;
12     }
13     #content{
14       box-sizing: border-box;
15       height: 100vh;
16       width: 100vw;
17       padding-top: 60px;
18       background-color: #87ceeb;
19       font-size: 60px;
20       text-align: center;
21       color: #fff;
22       overflow: hidden;
23     }
24   </style>
25 </head>
26 <body>
27   <div id="content">0</div>
28 </body>
29 <script>
30   function count() {
31     document.getElementById('content').innerHTML = Math.random().toFixed(6)
32     console.info(Math.random().toFixed(6))
33   }
34   // window.onmousemove = count
35 
36   // 防抖 - 超过时间间隔后触发一次处理函数
37   function debounce(func, wait) {
38     let timeout
39     return function () {
40       if (timeout) {
41         clearTimeout(timeout)
42       }
43       timeout = setTimeout(func, wait)
44     }
45   }
46   // window.onmousemove = debounce(count, 1000)
47 
48   // 防抖 - 先执行一次处理函数
49   function debounceAdvance(func, wait) {
50     let timeout
51     return function () {
52       let context = this
53       let args = arguments
54       if (timeout) {
55         clearTimeout(timeout)
56       }
57       let callNow = !timeout
58       timeout = setTimeout(() => {
59         timeout = null
60         func.apply(context, args)
61       }, wait)
62       if (callNow) {
63         func.apply(context, args)
64       }
65     }
66   }
67   window.onmousemove = debounceAdvance(count, 500)
68 </script>
69 </html>
View Code

2.节流throttle

节流是把高频操作降低到一段时间内(delay)执行一次,可以在第一次出发时创建一个时间戳prev,和再次触发事件的时间戳now比较,如果间隔大于delay就触发事件,重新计时

 1 // 时间戳版
 2 let throttle = function(func, delay){
 3   let prev = Date.now()
 4   return function() {
 5     let now = Date.now()
 6     if(now - prev >= delay){
 7       func()
 8       prev = Date.now()
 9     }
10   }
11 }
12 window.onmousemove = throttle(handle, 1000)

或者使用定时器完成,完整版:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4   <meta charset="UTF-8">
 5   <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6   <title>Throttle</title>
 7   <style>
 8     *{
 9       margin: 0;
10       padding: 0;
11       border: 0;
12     }
13     #content{
14       box-sizing: border-box;
15       height: 100vh;
16       width: 100vw;
17       padding-top: 60px;
18       background-color: #87ceeb;
19       font-size: 60px;
20       text-align: center;
21       color: #fff;
22       overflow: hidden;
23     }
24   </style>
25 </head>
26 <body>
27   <div id="content">0</div>
28 </body>
29 <script>
30   function handle() {
31     document.getElementById('content').innerHTML = Math.random().toFixed(6)
32     console.info(Math.random().toFixed(6))
33   }
34   // window.onmousemove = handle
35 
36   // 时间戳版
37   let throttle = function(func, delay){
38     let prev = Date.now()
39     return function() {
40       let now = Date.now()
41       if(now - prev >= delay){
42         func()
43         prev = Date.now()
44       }
45     }
46   }
47   // window.onmousemove = throttle(handle, 1000)
48 
49   // 定时器版
50   let throttle2 = function(func, wait){
51     let timeout
52     return function() {
53       if(!timeout){
54         timeout = setTimeout(()=>{
55           func()
56           timeout = null
57         }, wait)
58       }
59     }
60   }
61  
62   window.onmousemove = throttle2(handle, 1000)
63 
64 </script>
65 </html>
View Code

3.应用场景

常用于用户不断改变浏览器大小、鼠标移动和输入验证的一些处理,这些最后触发一次的使用防抖即可;

鼠标不断点击、鼠标滚动不断加载等适合使用节流throttle.

说下我的案例:

一个数据在线编辑平台,用户需要不断输入X、Y、Z坐标调整物体位置,希望不用离开输入框就能实时看到变化,如果监听keyup事件就会过于频繁,这时就适合使用防抖。

另外一个是在地图中加载了20w+模型,每次移动地图都会触发模型的重新渲染,这是就需要再地图的move事件中进行一些干预,可以用防抖,不过幸运的是地图有moveend事件,也算是一种防抖吧。

 

posted on 2020-08-05 11:13  橘生淮南_  阅读(182)  评论(0编辑  收藏  举报