1、事件频繁触发可能造成的问题?
(1)、一些浏览器事件: window.onresize、window.onmousemove等,触发的频率非常高,会造成浏览器性能问题。
(2)、如果向后台发送请求,频繁触发,对服务器造成不必要的压力;例如百度搜索时输入字符,每改变一下输入框字符时就去请求一下,如果不处理就会产生不必要的多余请求,给服务器产生压力。
2、如何限制事件处理函数的频繁调用
主要在于函数调用和函数执行之间的处理
(1)、函数节流
(2)、函数防抖
3、函数节流(throttle)
(1)、理解:
一个函数频繁触发调用,在一定时间T周期内只执行一次调用,实现原理有两种:
(a)、在一定时间T周期的最开始调用,立即执行:在一个函数频繁触发调用时,第一次调用函数立即执行,在往后规定时间T内再次调用该函数不再执行,直到规定时间T后再次调用函数理解执行,周期循环这一过程。
(b)、在一定时间T周期的最开始调用,经过时间T后执行:在一个函数频繁触发调用时,第一次调用函数使用计时器,当计时器经过一定时间T再执行函数,在这一定时间T内其他的函数不予执行。周期循环这一过程。
适合与多次事件按时间平价分配触发。
(2)、应用场景
窗口调整(onresize)
页面滚动(onscroll)
DOM元素拖拽(onmousemove)
抢购疯狂点击(onclick)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>throttle与debounce</title> </head> <body> <div> <button>(时间戳)节流函数</button> <button>(计时器)防抖函数</button> </div> </body> <script> window.onload = function () { // 以时间戳来实现返回节流函数的工具函数 function timeStampThrottle(callback, delay = 1000) { let pre = 0; //设置初始调用时间为0 return function (event) { const current = Date.now(); // 获取当前调用时间 if (current - pre > delay) { // 只用离上次调用callback的时间大于delay时才再次调用callback callback.call(this, event) // 调用真正处理事件的函数,this作为事件源,参数是event // 记录此次调用的时间 pre = current } } }; // 以计时器来实现返回节流函数的工具函数 function timeMeterThrottle(callback, delay = 1000) { let timer = null; return function (event) { if (!timer) { timer = setTimeout(() => { callback.call(this, event) timer = null; }, delay) } } }; function handleClick() { console.log("执行了函数", this, event); }; document.getElementsByTagName("button")[0].onclick = timeStampThrottle(handleClick, 2000); document.getElementsByTagName("button")[1].onclick = timeMeterThrottle(handleClick, 2000); } </script> </html>
4、函数防抖(debounce)
(1)、理解:
在一个函数频繁触发调用时,其中函数A调用后执行的条件是下一次函数B调用与函数A调用时间间隔大于规定时间T,且函数A执行的时间为函数A调用时的时间+规定时间T。
适合多次事件一个响应的情况
(2)、场景:
输入框实时搜索联想(keyup/input)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>debounce函数防抖</title> </head> <body> <div> <button>函数防抖</button> </div> </body> <script> window.onload = function () { function debounce(callback, delay) { return function (event) { // 如果上次事件还没有真正执行完成,取消它 if (callback.hasOwnProperty("timeoutId")) { clearTimeout(callback.timeoutId) }; // 启动定时器,在delay时间后执行 callback.timeoutId = setTimeout(() => { // 正在执行事件 callback.call(this, event); // 删除准备执行的标记 delete callback.timeoutId; }, delay); } }; function handleClick() { console.log("执行了函数", this, event); }; document.getElementsByTagName("button")[0].onclick = debounce(handleClick, 2000); } </script> </html>