有些浏览器事件会被用户在很短的时间内触发很多次,例如点击事件或滚动页面。如果你给窗口滚动事件添加一个事件监听函数(事件句柄),然后用户不停地快速上下滚动页面,那你的事件可能在一秒之内都会被触发很多次,这会导致严重的性能问题,比如说你的页面卡住了(假死),所以我们需要降低触发回调的频率。
下面就说一下优化这种高频执行js的方法,来提高页面速度和性能。
预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新的时间周期。(设置阈值)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> <title>函数防抖 - 打开控制台,滚动你的鼠标小滑轮试试看</title> <style> </style> </head> <body style="height:2000px;"> <h1>函数防抖</h1> </body> <script src="./jquery-2.1.4.min.js"></script> <script> var isThrottle = true; //初始化无需走节流 var setTimer = null; //初始化定时器 var throttle = function(fn, time) { clearInterval(setTimer) var time = time || 300; if (isThrottle) { //注意:在这里第一次滚动时候我们是需要立马执行函数的,真正的防抖是从第二次开始 fn(); isThrottle = false; return false; /*细节:这里如果你不return false阻断代码往下执行,那么在第一次时候实际还会走下面的else,也就是触发了两次,(因为滚轮触发的事件频率很高,第一次节流(else中)的事件会紧接着初始化第一次未节流事件去执行了)*/ } else { console.log('高频触发滚动事件中') setTimer = setTimeout(function() { fn(); isThrottle = true; console.log('上一次打印是节流执行。。。') }, time) } } function conduct() { console.log("1") } $(document).scroll(function() { throttle(conduct, 1000); }) </script> </html> |
注意:当你第一次滚动时候,方法不会执行,这当然是属于Bug了,在第一次滚动时候我们应该第一时间执行这个方法,也就是说,真正节流应该是从第二次滚动时候才开始进行,也就是所谓的防抖,它的做法是限制下次函数调用之前必须等待的时间间隔,
如果想处理好真正的节流,很显然,仅仅上面这样处理方式还是不够的,假设用户在mac触摸板下不停的滚动(我也是用mac才发现这个bug)这时候因为每次都会去触发节流函数,但是每次还没执行就被上一个清除定时器给清除了,所以在中途一直不会触发节流,只有每次用户停止才会去触发,很显然不可取,违背了我们的初衷,我们想要的是在第一次立即出发,中间高频率操作过程中间隔一定的时间去更新去出发,而不是必须傻傻的等待用户高频率触发完成后再去触发一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> <title>函数节流、防抖 - 打开控制台,滚动你的鼠标小滑轮试试看</title> <style> body { background: #fff; text-align: center; } h1 { font-size: 24px; line-height: 36px; margin-top: 100px; font-weight: normal; font-family: "微软雅黑" } a { color: #ed145b; } </style> </head> <body style="height:2000px;"> <h1>函数节流、防抖</h1> <p><a href="./index.html">点击前往—>函数防抖(并非节流)</a></p> </body> <script src="./jquery-2.1.4.min.js"></script> <script> function conduct(fn, delay, preTime) { var timer; var initTime = new Date(); // 初始时间点 console.log('初始化') return function (arg) { var nowTime = new Date(); // 当前最新时间 clearTimeout(timer) if (nowTime - initTime < preTime) { // 两次操作是否小于预设限制时间(preTime) timer = setTimeout(() => { fn(arg); initTime = nowTime; }, delay) } else { fn(arg); initTime = nowTime; } } } function Fn(data) { console.log(data) } var throttle = conduct(Fn, 1000, 2000) $(document).scroll(function () { throttle('1'); }) </script> </html> |
节流:n秒内只运行一次,若在 n 秒内重复触发,只有一次生效
防抖:n秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
一个经典的比喻:想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应,假设电梯有两种运行策略 debounce 和 throttle,超时设定为15秒,不考虑容量限制,电梯第一个人进来后,15秒后准时运送一次,这是节流。电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖。
上一篇:【ES7】Array.prototype.includes() PK indexOf
下一篇:JS获取网站地址栏URL中的参数值并转换成json对象
支付宝扫一扫打赏
微信扫一扫打赏
共 0 条评论关于"关于js函数节流与函数防抖【完美解决】"
最新评论