最简单的防抖和节流
防抖和节流很长一段时间不太懂什么意思,总觉得它们是一个东西。但是花了时间着重了解以后发现它们还是有不少区别的。
但是有个共同点就是都是使用setTimeOut定时器实现的。
1.防抖
特点:一个函数,短时间多次触发,但是只执行最后一次触发的事件
思路:将所有的消息推入消息队列,但是只执行最后一次的消息
用处:如一个点击发送请求的按钮。为了防止用户由于误触导致的多次点击。所以只执行短时间内多次触发的最后一次触发。
核心代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>防抖:只执行最后一次的操作(频繁请求的按钮)</h1> <button onclick="add()">点击添加</button> <h3 id="num"></h3> </body> <script> let n = 1 let h_n = document.getElementById("num") h_n.innerText = n let timer = null // 防抖的定时器 function add() { clearTimeout(timer) // 清除上一个定时器 timer = setTimeout(() => { h_n.innerText = ++n // 数字加1 }, 1000) } </script> </html>
说明:
- 以一个点击数字增加的例子说明
- 每次执行函数时都清除上一次的定时器。清除了这个定时器以后setTimeout内的代码(h_n.innerText = ++n)不再执行。
- 如果在一秒内再次触发了add函数,那么上一次触发的定时器将不再执行
事物队列解析:
- add()方法中的定时器数字加1的操作属于消息队列中的内容,而消息会在调用栈清空的时候执行
- 如果在短时间(定时器的1S时间内)再次触发了add()方法,此时会先将上一个定时器清除(清除以后,上一个数字加1的操作将不再执行)
- 对应的Event Loop的过程就是:把上一个进入消息队列的消息删除,这次新的消息将进入消息队列
2.节流
特点:持续触发情况下,只会在固定的时间间隔执行。比如百度的搜索显示下拉列表的功能
思路:只将肯定执行的消息推入消息队列
代码示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button onclick="add()">添加</button> <h1 id="cont"></h1> <script> let n = 1 let cont = document.getElementById("cont") cont.innerText = n let swch = true // 节流的开关 function add(){ if(swch) { swch = false setTimeout(()=>{ swch = true cont.innerText = ++n },1000) } } </script> </body> <style> body{ text-align: center; } </style> </html>
说明:
- add()方法内,判断一下开关是否打开,如果打开说明上一个定时器回调已经执行完毕,可以执行下一次函数。如果关闭,表示1s时间还没到,开关还没有打开,此时无法执行 ++n操作
事件队列解析:
- 有一个全局的开关,add()方法根据这个开关决定是否将该消息推入消息队列