前言
这是我参与更文挑战的第3天,活动详情查看更文挑战
函数防抖和节流是优化高频率执行js代码的一种手段。作为前端开发是必须要知道的,当然,也是面试的常考点之一,
防抖函数
原理:在事件被触发n秒后,再去执行回调函数。如果n秒内该事件被重新触发,则重新计时。结果就是将频繁触发的事件合并为一次,且在最后执行
案例
需求:输入框的结果是在我们键盘弹起时,在规定的时间内没有输入,就打印结果
let input = document.getElementById('input')
function debounce(delay){
let timer;
return function(value,callback){
clearTimeout(timer)
timer = setTimeout(function(){
callback(value)
},delay)
}
}
// 为了方便封装,把调试打印的结果以callback的形式传入
function fn(value){
console.log(value)
}
var debounceFn = debounce(1000)
input.addEventListener('keyup',function(e){
debounceFn(e.target.value,fn)
})
实际应用场景
-
使用echart时,改变浏览器宽度的时候,希望重新渲染echart的图像,可以使用此函数,提升性能。(虽然echarts里有自带的resize函数)
-
典型的案例就是模糊搜索:输入结束后n秒才进行搜索请求,n秒内又输入的内容,就重新计时。解决搜索的bug,要在请求之前拿到最后一次输入的结果
节流函数
当持续触发事件的时候,保证一段时间,只调用一次处理函数,(一段时间内,只做一件事情)
实际应用 表单的提交
典型的案例就是鼠标不断点击触发,规定在n秒内多次点击只有一次生效
// 如果不用闭包的话,就会你点击几次,就会执行几次
// 这不是我们想要的,我们想要的是,比如说,时间是一秒,哪怕你手速再快,一秒内,就算你点击了1000次,我也只执行一次
// 使用闭包的话,就会把变量保存在内存之中
function throttle(func,wait){
let timeOut
return function(){
if(!timeOut){
timeOut = setTimeout(function(){
func()
// 处理完之后就不处理了
timeOut = null
},1000)
}
}
}
function handle(){
console.log(Math.random())
}
document.getElementById('thro').onclick = throttle(handle,1000)
两者综合使用的案例
图片懒加载是我们前端开发中最常见的一种优化性能方式。下面这个是使用防抖节流后的案例。
html部分
<img src="" data-src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3205580013,1833705086&fm=26&gp=0.jpg" alt="" />
javascript部分
var num = document.getElementsByTagName('img').length
var img = document.getElementsByTagName('img')
var n = 0 // 存储图片加载到的位置,避免每次都从第一张图片开始遍历
var isLoadImg = false // 是否当前容器/页面里的图片已加载完成
var _clientHeight = document.documentElement.clientHeight // 可视区域高度
var _scrollTop = document.documentElement.scrollTop || document.body.scrollTop // 滚动条距离顶部高度
// 监听窗口变化 重新计算可视区域
function computedClientHeight(){
_clientHeight = document.documentElement.clientHeight // 可视区域高度
}
// 页面载入完毕加载可视区域的图片
lazyLoad()
function lazyLoad(){
// 获取滚动条距离顶部高度
isLoadImg = n >= num
_scrollTop = document.documentElement.scrollTop || document.body.scrollTop
for(var i=n;i < num;i++){
if(img[i].offsetTop <_clientHeight +_scrollTop) {
if (img[i].getAttribute('src')==''){
img[i].src = img[i].getAttribute('data-src')
}
n + 1
}
}
}
/**
* 简单的节流函数throttle
* @params {*}
* func 要要执行的函数
* delay 延迟
* time 在time时间内必须执行一次
* flag 是否继续触发节流函数(根据需求定义,这里就是想当加载完图片时不需要进行多余的操作
**/
function throttle(func,wait,flag){
let timeOut
return function(){
if (flag){
return
}
if(!timeOut) {
timeOut = setTimeout(function(){
timeOut = null
func()
},wait)
}
}
}
/**
* 简单的节流函数throttle
* @params {*}
* func 要要执行的函数
* delay 延迟
* time 在time时间内必须执行一次
* flag 是否继续触发节流函数(根据需求定义,这里就是想当加载完图片时不需要进行多余的操作
**/
function debounce(callback,delay) {
let timer
return function(arg) {
clearTimeout(timer)
timer = setTimeout(function(){
callback(arg)
},delay)
}
}
// 使用了节流函数-实现性能较好的懒加载
window.addEventListener('scroll',throttle(lazyLoad,100,isLoadImg))
// 使用防抖函数,优化不断触发的窗口变化
window.addEventListener('resize',debounce(computedClientHeight,800))