JavaScript 函数防抖
在前端开发中可能会遇到一些频发触发的事件,例如
- window 的 resize(浏览器窗口或者 HTML 对象改变大小)、scroll(滚动条事件)
- mousedown(鼠标在元素上按下事执行事件)、onmousemove(鼠标指针移动到元素上触发)
- keyup(按键被释放触发)、keydown(按键被按下触发)
举例
1 2 3 4 5 6 7 8 9
| HTML <style> #root{ width: 100%; height: 200px; line-height: 200px; text-align: center; color: #fff; background-color: #444; font-size: 30px; } </style> <div id='root'></div> <script src='./demo.js'></script>
|
1 2 3 4 5 6 7 8 9 10
| dome.js;
var conut = 1; var root = document.getElementById("root"); function getUserAction() { root.innerHTML = conut++; }
root.onmousemove = getUserAction;
|
效果如下
从图上可以看到从左边到右边一共触发了 160 多次 onmousemove 事件,同样执行了 160 多次 getUserAction 函数。
因为这个例子简单,浏览器可以处理的过来,如果换成请求, 频繁触发就会出现卡顿。
修改一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| dome.js
var conut = 1; var root = document.getElementById('root'); function getUserAction() { root.innerHTML = conut++; } function debounce(fn, wait) { var timeout; return function() { clearTimeout(timeout) 函数被执行了先清除先前定时器的返回值(传入一个错误的ID 给 clearTime 不会有任何影响(也不会抛出异常)) timeout = setTimeout(fn, wait); } } root.onmousemove = debounce(getUserAction, 1000);
|
上面这个函数
分析一下上面的操作
- 鼠标移动触发 onmousemove 事件。
- onmousemove 事件调用 debounce 函数
- debounce 函数接收到 getUserAction, 1000 函数之后返回一个匿名函数-清除前面的定时器-执行新的定时器
然后只要鼠标移动就会 1-2-3 执行,直至鼠标停留超过一秒,才会执行 getUserAction 函数。
JavaScript 节流
节流就是如果持续触发事件,则每个一段时间,只执行一次事件。
主流有两种方法:使用时间戳
, 设置定时器
使用时间戳
使用时间戳,当事件触发时,去除当前的时间戳,然后减去之前的时间戳,最开始可以设置为 0,如果大于设置的时间周期,就执行函数,然后更新时间戳为当前时间戳,如果小于,则不执行。
1 2 3 4 5 6 7 8 9 10 11 12 13
| function throttle(fu, wait) { var previos = 0; return () => { var now = +new Date(); if (now - previous > wait) { fu(); previous = now; } }; }
root.onmousemove = throttle(getUserAction, 1000);
|
使用定时器
当事件被触发的时候设置一个定时器,在触发事件,如果定时器存在则不执行,直至定时器执行然后执行函数,清空定时器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function throttle(fn, wait) { var timeout; return () => { if (!timeout) { timeout = setTimeout(() => { timeout = null; fn(); }, wait); } }; } root.onmousemove = throttle(getUserAction, 1000);
|