什么是函数防抖,通俗的讲就是节省开支
我们作为前端开发者,最最最主要的莫过于性能了,我们要想家庭主妇一样去精打细算,介绍不必要的开支,提升用户体验。
举个例子,当用户在搜索框输入要查询的字符串的时候,浏览器不断在监听input的输入事件,每输入一个字符,都监听一次。
$('input').on('input', function(){
let input = this
let ul = document.querySelector('#suggestion')
if (input.value) {
console.log(input);
search(input.value, function(words) {
ul.innerHTML = ''
for (var i = 0; i < words.length; i++) {
let li = document.createElement('li')
li.innerText = words[i]
ul.appendChild(li)
}
}) // undefined
} else {
ul.innerHTML = ''
}
})
从图中可以看到,每输入一个字符,都监听一次,这么做有个缺点就是消耗性能,浏览器会无时不刻地在计算input的输入,但是在实际场景中,我们可以等等用户输入完在去计算,怎么判断用户是否输入完呢?我们可以加个定时器,一旦时间到了,就默认用户输入完了,这个时候再去计算,就会节省性能。
而函数防抖所做的工作就是每隔一段时间去执行一次原本需要无时不刻地在执行的函数。
var timerId
$('input').on('input', function() {
let input = this
let ul = document.querySelector('#suggestion')
if (timerId) {
clearTimeout(timerId)
}
timerId = setTimeout(function() {
if (input.value) {
console.log(input);
search(input.value, function(words) {
ul.innerHTML = ''
for (var i = 0; i < words.length; i++) {
let li = document.createElement('li')
li.innerText = words[i]
ul.appendChild(li)
}
}) // undefined
} else {
ul.innerHTML = ''
}
}, 220)
})
我们在来看下控制台,在设定的时间里,输入了6个字符串,但是才监听一次,是不是相对之前的代码,优化了些呢?
简单来说,就是保存一个标记 timerId,
在事件内部去判断这个标记存不存在,如果存在就清除这个标记clearTimeout(timerId)
setTimeout的作用就是在设定的220ms之后去执行,在220ms这个时间范围之内,也就是timerId存在,就不执行search函数
防抖的原理就是:
尽管触发事件,但是在事件触发后的n秒才执行,如果你在事件触发的n秒之内又触发一次这个事件,就以新的事件为准,n秒之后执行,总之就是在你触发完事件的n秒之内不再触发新的事件,我才执行。
最后再封装下代码,主要是要避免全局变量!避免全局变量!避免全局变量!主要的话说三遍!
function debounce(method, delay) {
var timer
let ul = document.querySelector('#suggestion')
return function() {
var input = this
clearTimeout(timer);
timer = setTimeout(function() {
if (input.value) {
console.log(input);
search(input.value, function(words) {
ul.innerHTML = ''
for (var i = 0; i < words.length; i++) {
let li = document.createElement('li')
li.innerText = words[i]
ul.appendChild(li)
}
}) // undefined
} else {
ul.innerHTML = ''
}
}, delay);
}
}
$('input').on('input', debounce(function() {
console.log('input')
}, 220));
同时记一个坑,
最近在用es6的箭头函数,但是在事件函数中,箭头函数的this的指向问题,
假如实在要写箭头函数,那你就要确定this
自己看区别,箭头函数中,this指向的是window
es5中,this指向事件本身
document.querySelector('.btn1').onclick = ()=>{
console.log(this);
}
document.querySelector('.btn2').onclick = function(){
console.log(this);
}
解决办法:
document.querySelector('.btn1').onclick = (e)=>{
let that = e.target
console.log(that);
}
document.querySelector('.btn2').onclick = function(){
console.log(this);
}