JS面试题---防抖和节流
一、防抖
问题场景:有时会遇到这样一个情况,比如在一个搜索框里面进行搜索,在没有进行函数防抖的情况下,当我们在输入框中修改里面的值,我们想要的是等我们输入完成后再执行对输入关键字的搜索,这里就开始出现问题,如下面的例子。
<!DOCTYPE html> <html lang="en"> <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> <script> window.onload = function() { // 模拟ajax请求,传入的是待搜索的内容 let count = 0; function ajax(params) { console.log(这是第+(++count)+次请求,内容是:+params); } // 绑定输入框 let search = document.getElementById(serach); search.onkeyup = function(e) { //调用ajax ajax(e.target.value) } } </script> </head> <body> <div> <span>请输入搜索内容</span> <input id="serach" type="text"> </div> </body> </html>
可以看到由于我们短时间触发了多次事件,导致不停的调用ajax,可是最后一次请求才是我们需要的,这叫造成了资源的浪费,因此我们必须通过防抖函数来杜绝这个现象。
原理概念:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
代码实现:
<script> window.onload = function() { // 模拟ajax请求,传入的是待搜索的内容 let count = 0; function ajax(params) { console.log(这是第+(++count)+次请求,内容是:+params); } // func是用户执行的功能,wait是等待时间 const debounce = (func,wait = 100) => { // 缓存一个定时器 let timer = 0; // 返回的函数是每次调用的防抖函数 return function(...args) { // 如果已经开启过定时器,那么这里就是清空上一次的定时器 if(timer) { clearTimeout(timer); } // 如果没有,则定义一个新的定时器,延长用户传入的方法 timer = setTimeout(() => { func.apply(this,args); },wait) } } // 绑定输入框 let search = document.getElementById(serach); // 给ajax绑定防抖函数 let debounceA = debounce(ajax,1000); search.onkeyup = function(e) { // 在有防抖函数下调用ajax // ajax(e.target.value) debounceA(e.target.value) } } </script>
可以看到,因为我传入的等待时间是1s,所以只有当输入停下来,并且超过一秒没有触发键盘时间才会发送请求。到这里,防抖的功能也就实现了。(在按钮提交,为了防止多次按钮提交,表单验证都可以使用到防抖函数)
二、节流
问题场景:我们平常在百度时,比如要搜索一个人的信息— 卢·猫之守护者·哮喘症征服者·被光选中的人·迪,讲道理这么长的名字很可能记不住 ,但是防抖函数又会延迟搜索,如果这个时间很大(3s),本来用户输入 卢·猫就能准确的找到,但是只有等3s后才能给出信息,就会非常影响用户的体验,可能有小伙伴会想,我直接在防抖函数把延迟执行的值改小一点不就行了吗?这样做是可以,但是会造成该防抖函数的适用性小,非常不灵活,所以需要另一种方法—节流。
原理概念:规定在一个单位时间内,只能触发一次函数。如果这个函数时间触发多次函数,只有一次有效。和防抖函数差不多。
代码实现:
<script> window.onload = function() { // 模拟ajax请求,传入的是待搜索的内容 let count = 0; function ajax(params) { console.log(这是第+(++count)+次请求,内容是:+params+ +new Date().getSeconds()); } // func是用户执行的功能,wait是等待时间 const throttle = (func,wait = 100) => { // 上一次执行函数的时间 let lastTime = 0; // 返回的函数是每次调用的防抖函数 return function(...args) { // 当前时间 let now = +new Date(); // 如果当前时间和上一次执行时间的差值大于等待时间,则执行函数 if(now - lastTime > wait) { lastTime = now; func.apply(this,args); } } } // 绑定输入框 let search = document.getElementById(serach); // 给ajax绑定防抖函数 let throttleA = throttle(ajax,1000); search.onkeyup = function(e) { // 在有节流函数下调用ajax // ajax(e.target.value) throttleA(e.target.value) } } </script>
可以看到,节流函数设置的延迟时间是1s,不论我们在这1s内触发多少次键盘事件,ajax请求只会执行一次。(在图片的拖拽中,不用节流会造成卡顿,使用节流会流畅许多)