我们给一个inpu输入框绑定一个oninput事件,此时我们输入“前端开发”四个字,我们
观察以下后台打印
Document
我们仅仅输入四个字,就触发了几十次事件,
如果说我每一次输入都和后台进行数据交互,那么将会很影响计算机的性能。
因此我们需要让请求的次数大大减少,因此我们需要利用防抖来减少用户操作过多,与后台数据交互的次数。
接下来我们来介绍防抖
防抖:用户触发事件过于频繁,只要最后一次事件的操作。
也就是说,用户频繁的操作,我们只取最后一次操作。
比如
同样我们输入‘前端开发’四个字,如果我们输入的时间间隔小于0.5秒,就不触发oninput事件,
如果我们输入的时间间隔大于0.5秒,那么我们就触发oninput。
这样我们就大大减少了请求的次数。
Document
如图,我们只要输入的时间间隔小于0.5秒,就不会触发oninput事件,只有当我们的输入的时间间隔超过0.5秒时,才会触发该事件。对比之下,我们触发的次数少了很多。
虽然以上代码完成了防抖的效果,但是还可以再优化一下,为什么要优化呢
在我们写的代码中只有console.log(this.value) 是真正的业务逻辑代码
而且我们还定义了一个全局变量t,
以及这部分是防抖代码和业务代码混在一起,
//防抖的逻辑和业务逻辑混在一起了
if (t !== null) {
clearTimeout(t)
}
t = setTimeout(() => {
console.log(this.value) //真正的业务逻辑代码
}, 500)
,而且该部分代码可读性不太好,别人需要看半天才知道是防抖,因此我们需要优化一下。
我们可以通过闭包来优化防抖代码
使用闭包可以不用产生全局变量t,并且可以让防抖代码与业务代码隔离;
Document
很多人看到这里可能一头雾水,突然有点看不懂了,别着急,我来慢慢解释。
这里我们定义了一个防抖函数debounce
inp.oninput = debounce();
function debounce() {//防抖函数
return function() {
}
}
我们知道inp.oninput事件=一个函数,
所以debounce返回一个函数,并且我们需要将相关逻辑作为参数,传给debounce
inp.oninput = debounce(function(){},500);//参数function(){}中执行业务代码,500是传入的延时时间
function debounce(fn,delay) {//fn是要执行的业务逻辑,是函数//delay为定时器的延时事件
let t=null;
return function() {
if (t !== null) {
clearTimeout(t)
}
t = setTimeout(() => {
fn(); //执行的业务代码
}, delay)
}
}
接着
inp.oninput = debounce(function() {
console.log(this.value)
}, 500);
function debounce(fn, delay) {
let t = null;
return function() {
if (t !== null) {
clearTimeout(t)
}
t = setTimeout(() => {
fn();
}, delay)
}
}
我们运行一下代码,输入
发现输出的是undefind
inp.oninput = debounce(function() {
console.log(this)//打印this
}, 500);
function debounce(fn, delay) {
let t = null;
return function() {
if (t !== null) {
clearTimeout(t)
}
t = setTimeout(() => {
fn();
}, delay)
}
}
因此我们需要在改变this的指向,也就是改变参数fn的this的指向
inp.oninput = debounce(function() {
console.log(this)//打印this,指向window
}, 500);
function debounce(fn, delay) {
let t = null;
return function() {
if (t !== null) {
clearTimeout(t)
}
t = setTimeout(() => {
console.log(this)//指向input
fn();//fn的this指向window
}, delay)
}
}
改变this指向后的代码
inp.oninput = debounce(function() {
console.log(this.value)
}, 500);
function debounce(fn, delay) {
let t = null;
return function() {
if (t !== null) {
clearTimeout(t)
}
t = setTimeout(() => {
fn.call(this);//通过call改变this指向
}, delay)
}
}
这样防抖代码优化完了。
完整代码如下:
Document
什么是节流?
节流:控制高频事件的执行次数(事件频繁触发时,每隔多少秒触发一次)
防抖是只执行最后一次,而节流是减少执行次数。
我们先做一个滚动事件,只要我们让滚动条滚动就会打印123,如下图,我们只是滚动了一下,
就触发了一百多次,如果是和后台服务器产生数据交互,同样对性能消耗是比较大的。
因此我们需要节流。
Document
此时需要节流,来减少执行的次数
Document
代码优化后
window.onscroll = throttle(function() {
console.log(123);
}, 500)
function throttle(fn, delay) {
let flag = true;
return function() {
if (flag) {
setTimeout(() => {
fn.call(this);
flag = true;
}, delay)
}
flag = false;
}
}