概念
什么是防抖?什么是节流?
首先我们先记住2句话,我们带着这2句话进行下面的探讨
1.防抖就是在一定时间内,仅最后一次生效的任务
2.节流就是在一定时间内,仅第一次生效的任务
防抖运用
首先我们要先清楚我们什么为什么要用防抖函数,我们在那些地方可以用到防抖函数?
首先我们可以先看一下以下的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text">
<script>
let input = document.querySelector('input');
input.oninput = function () {
console.log(this.value)
}
</script>
</body>
</html>
当我们执行这串代码的时候,我们在输入框输入内容时,事件就会被触发,我们就可以发现,这个事件是否触发的太快了,假如我们每一次输入不再是简单的打印console.log,而是在其中加入一些网络请求与后台进行交互,我们就会发现,这样的交互太频繁了,会给我们的服务器造成很大的压力,降低我们的性能,所以我们就要通过一些方法让我们的交互变得不那么频繁,所以我们就需要引入防抖的概念,防抖所完成的需求就是用户操作过于频繁,我们只要进行最后一次的操作。
所以我们对之前的函数进行改进
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text">
<script>
let input = document.querySelector('input');
let t = null;
input.oninput = function () {
if (t !== null){
clearTimeout(t)
}
t = setTimeout(() =>{
console.log(this.value)
},500)
}
</script>
</body>
</html>
在我们执行这串函数时我们先在全局环境下去定义一个计时器的t,我们把它的初始值设置为null,我们把我们最终要执行的代码放在一个settimeout里面(注意settimeout函数为箭头函数,因为这样好调节内部函数的this指向),并将他的返回值赋值给t,当我们第一次触发这个事件时,我们先对这个计时器t进行判断,如果这个t为null我们就会跳过if语句执行settimeout的函数,当我们在settimeout函数还没执行完成时候,我们第二次触发了这个事件,由于闭包的特性,此时t已经不再是null了,所以第二次执行就会进入if语句中,在if语句中我们将t清除,就相当于把第一次正在执行的settimeout进行了清除,清除完成之后便跳出if语句,执行一个新的settimeout函数,以此类推,我们就可以发现,当我们快速的在函数要求时间内连续执行的时候,他会不断的将t清空,只执行你最后一次的操作,这就是防抖最基本的应用。
在初步了解了防抖后我们可以简单的对防抖函数进行一个封装
let input = document.querySelector('input');
input.oninput = debounde(function () {
console.log(this.value)
},500)
function debounde(fn,delay) {
let t = null;
return function () {
if (t !== null){
clearTimeout(t)
}
t = setTimeout(() =>{
fn.call(this)
},delay)
}
}
在封装代码中我们可以看到我们创建了一个debouned函数,并将我们主要执行的业务函数fn()当做一个回调函数放在debounde的函数中进行调用,在这其中我们还要注意一点就是在fn中的this指向的问题,如果我们采用fn()进行直接调用我们就会发现此时的this指向的是windows全局对象,所以我们要将fn函数的this指向此时的input对象,我们采用call方法调用来改变fn中this的指向问题。在我们平时在浏览器搜索框搜索时一般都有应用防抖函数进行优化
节流应用
在通过初步学习完防抖函数后,我们接下来认识一下节流函数
我们首先来看一下这个场景
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
height: 2000px;
}
</style>
</head>
<body>
<script>
window.onscroll = function () {
console.log('hello world')
}
</script>
</body>
</html>
当我们给整个页面页面设置一个2000px的高度,我们给屏幕的滚动的事件我们就会发现当我们一滚动,事件的触发就会过于频繁,假如我们滚动不是单单的触发console.log事件,而是一些比较耗性能的事件或者是一切交互数据的事件,只要我们一滚动,就会频繁的触发,所以我们就需要引入节流函数的概念,节流所完成的需求就是事件触发过于频繁,控制执行次数,我们只要进行第一次的操作。
由于节流与防抖十分的相似,所以我们直接来对节流函数进行封装
window.onscroll = throttle(function () {
console.log('hello,world')
},500)
function throttle(fn,delay) {
let flag = true
return function () {
if (flag){
setTimeout(() =>{
fn.call(this)
flag = true
},delay)
}
flag = false
}
}
在上串代码中,我们首先定义一个flag,让其最开始为true,只有放我们的flag为true时他才会执行业务代码的逻辑,当它执行一次我们就把flag的值改为false,当我们第一次执行的时候,flag此时为true,他就会执行业务代码的逻辑,然后我们在第一次还没执行完成时候去执行第二次我们就会发现,因为settimeout为异步函数还在执行,而此时flag的值以为被改为false了,在settimeout还没执行完之前一直都是false,所以第二次就无法执行,所以我们就只会在一段时间内只执行第一次的操作,以此来达到节流的效果。