一、防抖
问题场景:有时会遇到这样一个情况,比如在一个搜索框里面进行搜索,在没有进行函数防抖的情况下,当我们在输入框中修改里面的值,我们想要的是等我们输入完成后再执行对输入关键字的搜索,这里就开始出现问题,如下面的例子。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
window.onload = function() {
// 模拟ajax请求,传入的是待搜索的内容
let count = 0;
function ajax(params) {
console.log('这是第'+(++count)+'次请求,内容是:'+params);
}
// 绑定输入框
let search = document.getElementById('serach');
search.onkeyup = function(e) {
//调用ajax
ajax(e.target.value)
}
}
</script>
</head>
<body>
<div>
<span>请输入搜索内容</span>
<input id="serach" type="text">
</div>
</body>
</html>
可以看到由于我们短时间触发了多次事件,导致不停的调用ajax,可是最后一次请求才是我们需要的,这叫造成了资源的浪费,因此我们必须通过防抖函数来杜绝这个现象。
原理概念:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
代码实现:
<script>
window.onload = function() {
// 模拟ajax请求,传入的是待搜索的内容
let count = 0;
function ajax(params) {
console.log('这是第'+(++count)+'次请求,内容是:'+params);
}
// func是用户执行的功能,wait是等待时间
const debounce = (func,wait = 100) => {
// 缓存一个定时器
let timer = 0;
// 返回的函数是每次调用的防抖函数
return function(...args) {
// 如果已经开启过定时器,那么这里就是清空上一次的定时器
if(timer) {
clearTimeout(timer);
}
// 如果没有,则定义一个新的定时器,延长用户传入的方法
timer = setTimeout(() => {
func.apply(this,args);
},wait)
}
}
// 绑定输入框
let search = document.getElementById('serach');
// 给ajax绑定防抖函数
let debounceA = debounce(ajax,1000);
search.onkeyup = function(e) {
// 在有防抖函数下调用ajax
// ajax(e.target.value)
debounceA(e.target.value)
}
}
</script>
可以看到,因为我传入的等待时间是1s,所以只有当输入停下来,并且超过一秒没有触发键盘时间才会发送请求。到这里,防抖的功能也就实现了。(在按钮提交,为了防止多次按钮提交,表单验证都可以使用到防抖函数)
二、节流
问题场景:我们平常在百度时,比如要搜索一个人的信息— 卢·猫之守护者·哮喘症征服者·被光选中的人·迪,讲道理这么长的名字很可能记不住 ,但是防抖函数又会延迟搜索,如果这个时间很大(3s),本来用户输入 卢·猫就能准确的找到,但是只有等3s后才能给出信息,就会非常影响用户的体验,可能有小伙伴会想,我直接在防抖函数把延迟执行的值改小一点不就行了吗?这样做是可以,但是会造成该防抖函数的适用性小,非常不灵活,所以需要另一种方法—节流。
原理概念:规定在一个单位时间内,只能触发一次函数。如果这个函数时间触发多次函数,只有一次有效。和防抖函数差不多。
代码实现:
<script>
window.onload = function() {
// 模拟ajax请求,传入的是待搜索的内容
let count = 0;
function ajax(params) {
console.log('这是第'+(++count)+'次请求,内容是:'+params+' '+new Date().getSeconds());
}
// func是用户执行的功能,wait是等待时间
const throttle = (func,wait = 100) => {
// 上一次执行函数的时间
let lastTime = 0;
// 返回的函数是每次调用的防抖函数
return function(...args) {
// 当前时间
let now = +new Date();
// 如果当前时间和上一次执行时间的差值大于等待时间,则执行函数
if(now - lastTime > wait) {
lastTime = now;
func.apply(this,args);
}
}
}
// 绑定输入框
let search = document.getElementById('serach');
// 给ajax绑定防抖函数
let throttleA = throttle(ajax,1000);
search.onkeyup = function(e) {
// 在有节流函数下调用ajax
// ajax(e.target.value)
throttleA(e.target.value)
}
}
</script>
可以看到,节流函数设置的延迟时间是1s,不论我们在这1s内触发多少次键盘事件,ajax请求只会执行一次。(在图片的拖拽中,不用节流会造成卡顿,使用节流会流畅许多)