在前端js防抖节流时,一般用于搜索,鼠标,键盘滚动等触发事件,以防止连续触发执行导致浏览器CPU或网络等占用。
防抖
防抖策略就是当一个事件被触发后,延迟几秒在执行回调函数,如果在这几秒内又被触发了,那么就会重新计时
主要应用场景:
频繁操作dom,发送请求
视图窗口变化window的 resize
键盘事件:文字输入时的 keyup 事件
鼠标事件:元素拖拽、移动时的 mousemove 事件;
按钮的不断点击;
滚轮滚动scroll 事件
输入框搜索
在用户输入时连续输入一串字符,可以通过防抖策略只有在输入完毕过后再去执行查询的请求这样可以有效减少请求次数。
具体怎么来实现需要一个定时器,然后定义防抖函数,这个函数里面开启定时器获取jsonp数据渲染html都在这里面调用,在用户键盘事件这里清除定时器,输入一个清除一个输入一个清除一个,所以只要输入的够快,就达不到进入执行这个定时器的门槛,当你停下输入正常执行代码,就会开始执行定时器,去调用去请求去渲染
实例代码:
$(function() { // 防抖1 定义一个延时器 var timer = null // 防抖2 定义防抖函数 function debounceSearch(text) { timer = setTimeout(() => { getSearchList(text) }, 500); } // 1.先获取输入框的文字 $('.ipt').on('keyup', function(e) { // 防抖3一进来先清除定时器,按一下清一下 clearTimeout(timer) let iptText = $(this).val().trim() if (iptText == '') { // 4.搜索关键词为空时需要隐藏搜索列表 return $('.suggest-list').empty().hide() } else { // 2.1调用获取关键字函数 // getSearchList(iptText) // 防抖4 调用获取关键字函数由定时器执行相当于等你输完了在执行 debounceSearch(iptText) } }) // 2.封装获取建议列表的函数 function getSearchList(text) { $.ajax({ url : 'http://suggest.taobao.com/sug?q='+text+'', dataType : 'jsonp', success : res => { getHtml(res) } }) } // 3.3调用函数并渲染 function getHtml(res) { if (res.result.length <= 0) { return $('.suggest-list').empty().hide() } else { let htmlStr = template('suggestList', res) console.log(htmlStr); $('.suggest-list').html(htmlStr).show() } } })
缓存搜索
就是当我们输入一个数据的时候又添加一个关键字,然后删了有输入第一个关键字这个时候请求了三次,其中第一次和第三次是重复的,怎么解决
先定义一个全局的缓存对象,将搜索结果缓存到缓存对象中,优先从缓存中获取数据.
$(function() { // 防抖1 定义一个延时器 var timer = null // 防抖2 定义防抖函数 function debounceSearch(text) { timer = setTimeout(() => { getSearchList(text) }, 500); } // 缓存1 定义一个全局空对象 var resObj = {} // 1.先获取输入框的文字 $('.ipt').on('keyup', function(e) { // 防抖3一进来先清除定时器,按一下清一下 clearTimeout(timer) let iptText = $(this).val().trim() if (iptText == '') { // 4.搜索关键词为空时需要隐藏搜索列表 return $('.suggest-list').empty().hide() } else { // 缓存3 当我们输入值得时候就去判断一下有没有对象里有没有该值如果有那直接渲染就是不用再去请求数据 if (resObj[iptText]) { getHtml(resObj[iptText]) } else { // 2.1调用获取关键字函数 // getSearchList(iptText) // 防抖4 调用获取关键字函数由定时器执行相当于等你输完了在执行 debounceSearch(iptText) } } }) // 2.封装获取建议列表的函数 function getSearchList(text) { $.ajax({ url : 'http://suggest.taobao.com/sug?q='+text+'', dataType : 'jsonp', success : res => { console.log(res); getHtml(res) } }) } // 3.3调用函数并渲染 function getHtml(res) { if (res.result.length <= 0) { return $('.suggest-list').empty().hide() } else { let htmlStr = template('suggestList', res) // console.log(htmlStr); $('.suggest-list').html(htmlStr).show() // 缓存2 一切获取数据输入完毕在这里获取输入的最终值保存进对象里 resObj[$('.ipt').val().trim()] = res } } })
节流
节流策略就是可以减少一段时间事件的触发频率,通过一个节流阀达到本不需要这么高的触发率,让资源空出来
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> html,body { margin: 0; padding: 0; } img { position: absolute; } </style> </head> <body> <img src="./angel.gif" alt=""> <script> /* 普通版 var img = document.querySelector('img') document.onmousemove = function(e) { // console.log(11); img.style.left = e.pageX + 'px' img.style.top = e.pageY + 'px' } */ // 节流版 var img = document.querySelector('img') var timer = null document.onmousemove = function(e) { // console.log(11); if (timer) { return } else { timer = setTimeout(function() { img.style.left = e.pageX + 'px' img.style.top = e.pageY + 'px' timer = null },16) } console.log(11); } </script> </body> </html>
为什么要用到防抖和节流
前端代码的执行是基于浏览器的,频繁的进行某些计算或处理会占用更多的内存和CPU时间,可能会导致浏览器挂起,甚至是崩溃。
防抖和节流即是为了限制JS频繁的执行一段代码
防抖节流的定义及区别
防抖
连续的多次触发,固定的时间间隔内,存在新的触发,就清除之前的重新记时,满足时间执行一次——最新一次触发
节流
连续的多次触发,每一段固定的时间间隔内,我们只去执行一次——固定频率触发
各自的函数实现
防抖函数
/** *fn:真正需要执行的函数 *delay:延时时间 */ function debounce(fn, delay) { var timer = null; //这里使用闭包,方便我们自定义一些内部数据 return (...args) => { if (timer) clearTimeout(timer); timer = setTimeout(() => { //使用apply确保方法在适当的环境中执行 fn.apply(this,args); }, delay); } }
节流函数
/** *fn:真正需要执行的函数 *delay:延时时间 */ function throttle(fn, delay){ var last = null, return function () { const now = + Date.now() if(now > last + delay){ last = now fn.apply(this,args) } } }
实例代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>函数防抖节流</title> </head> <style> .mytest{ width: inherit; height: 200px; background-color: antiquewhite; align-items: center; font-size: 50px; display: flex; justify-content: center; } </style> <body> <div >0</div> </body> <script> function debounce(fn, delay) { var timer = null; return function () { if (timer) clearTimeout(timer); var _this = this; var _arguments = arguments; timer = setTimeout(function () { fn.apply(_this,_arguments); }, delay); } } function throttle(fn, delay){ var timer = null, booleanVal = false; return function () { if (booleanVal) { return } booleanVal = true; var _this = this; var _arguments = arguments; timer = setTimeout(function() { fn.apply(_this,_arguments); booleanVal = false; },delay) } } var div = document.querySelector('.mytest'); function foo() { div.innerHTML = ++foo.count; } foo.count = 0; div.onmousemove = throttle(foo,500); </script> </html>