防抖
出现原因
在一些频繁的事件处理中,需要频繁的操作DOM,但是让浏览器频繁的对DOM进行操作是及其消耗浏览器性能的,我们不建议这样做。我们可以在事件结束之后再去进行相应的操作,这样就会把频繁的操作转为只有当事件结束之后才会最终触发一次。
原理
对处理函数进行延时,如果在设定的延时到来之前,再次触发事件处理函数,则会清除上一次的延时,重新定时。
应用场景
做网页的回到顶部按钮,需要实时监听滚动条距离顶部距离
做search模糊搜索时,需要实时获取input框输入值
监听浏览器resize时
…
下面是一个封装的防抖函数(低配版)function debounce(method, delay) { let timer = null; return function() { let self = this; let args = arguments; timer && clearTimeout(timer); timer = setTimeout(function() { method.apply(self, args); }, delay); } } window.onscroll = debounce(function() { let tops = document.body.scrollTop || document.documentElement.scrollTop; console.log('tops', tops); }, 300)
防抖函数(高配版)
function debounce (func, wait = 50, immediate = true) { let timer, context, args // 延迟执行函数 const later = () => setTimeout(() => { // 延迟函数执行完毕,清空缓存的定时器序号 timer = null // 延迟执行的情况下,函数会在延迟函数中执行 // 使用到之前缓存的参数和上下文 if (!immediate) { func.apply(context, args) context = args = null } }, wait) // 这里返回的函数是每次实际调用的函数 return function(...params) { // 如果没有创建延迟执行函数(later),就创建一个 if (!timer) { timer = later() // 如果是立即执行,调用函数 // 否则缓存参数和调用上下文 if (immediate) { func.apply(this, params) } else { context = this args = params } // 如果已有延迟执行函数(later),调用的时候清除原来的并重新设定一个 // 这样做延迟函数会重新计时 } else { clearTimeout(timer) timer = later() } } } // 调用 document.getElementById('btn').onclick = debounce(function() { console.log('input value is: ', document.getElementById('inp').value || 'null') }, 1000, true)
防抖和节流本质上是不一样的,防抖是将多次操作变为最后一次操作,而节流是将多次操作变为连续多个间隔去执行
节流
定义
当函数事件触发后,短时间间隔内无法再次调用,只有当上一次函数执行完毕,且过了规定的时间间隔之后才会继续执行下一次的事件处理函数调用
原理
如果事件被连续触发超过某个固定的时间,就执行一次,周而复始。let startTime = Date.now(); //开始时间 let time = 500; //间隔时间 let timer; window.onscroll = function throttle(){ let currentTime = Date.now(); if(currentTime - startTime >= time){ let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滚动条位置:' + scrollTop); startTime = currentTime; }else{ clearTimeout(timer); timer = setTimeout(function () { throttle() }, 50); } }