“我叫夯大力,我以为不设置防抖节流就能写出高效的代码,要不是入职第二天就被公司开除了,我差点就信了。”
来,让我们看看这段罪魁祸首的源代码
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户搜索</title>
</head>
<body>
<div>
<label for="unDebounceInput">用户搜索</label>
<input
type="text"
id="unDebounceInput"
placeholder="请输入要搜索的用户名字"
>
</div>
<div>
<ul id="users">
</ul>
</div>
<script>
// 获取无序列表元素
const oUL = document.querySelector('#users');
// 获取输入框元素
const oInput = document.getElementById('unDebounceInput');
oInput.addEventListener('keyup', handleNameSearch)
// 处理用户搜索的函数
function handleNameSearch(){
// 获取输入框的值,并去除前后空格
let value = oInput.value.trim();
// 如果输入框为空,清空无序列表的内容并返回
if (value == '') {
oUL.innerHTML = '';
return;
}
// 使用fetch向后端接口发送请求,获取用户数据
fetch('http://localhost:3001/users')
.then(res => res.json()) // 将响应转换为JSON格式
.then(users => {
// 使用filter方法筛选出名字包含输入值的用户
const filterUsers = users.filter(user => user.name.includes(value));
// 使用map方法将筛选后的用户数组转换为HTML字符串,并设置为无序列表的内容
oUL.innerHTML = filterUsers.map(user =>
`<li>${user.name}</li>`
).join("");
})
.catch(error => {
console.error('获取用户数据时出错:', error);
});
}
</script>
</body>
</html>
后端数据
{
"users": [
{
"id": "1",
"name": "夯大力"
},
{
"id": "2",
"name": "白晶"
},
{
"id": "3",
"name": "小明"
}
]
}
分析
这里的后端项目是通过使用json-server来模拟后端服务器处理数据的
步骤
1.创建一个后端文件,并初始化:npm init -y
2.安装json-server :npm i json-server
3.将package.json中script部分改为: "dev": "json-server --watch db.json --port 3001"
然后输入:npm run dev
启动
代码分析
- HTML部分
-
创建了一个基本的HTML结构,包含一个输入框和一个无序列表。
-
输入框用于用户输入搜索关键词,
id
为unDebounceInput
。 -
无序列表
<ul>
用于显示搜索结果,id
为users
。
- JavaScript部分:
-
oUL
和oInput
分别获取了<ul>
和<input>
元素。 -
为输入框添加了
keyup
事件监听器,当用户在输入框中输入内容时,会触发handleNameSearch
函数。 -
handleNameSearch
函数:- 获取输入框的值,并去除前后空格。
- 如果输入框为空,则清空
<ul>
的内容并返回。 - 使用
fetch
向后端接口http://localhost:3001/users
发送请求,获取用户数据。 - 使用
filter
方法筛选出名字包含输入值的用户。 - 使用
map
方法将筛选后的用户数组转换为HTML字符串,并设置为<ul>
的内容。 - 添加了一个
catch
块来捕获并处理可能的错误。
运行结果
可以看到,我仅仅是输入了一个小明,结果直接给我整出一列的请求了,这还得了,要是公司的项目,那不得把服务器给整瘫痪了?
接下来我们加入防抖函数,看看
优化后的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户搜索</title>
</head>
<body>
<div>
<label for="unDebounceInput">用户搜索</label>
<input
type="text"
id="unDebounceInput"
placeholder="请输入要搜索的用户名字"
>
</div>
<div>
<ul id="users">
</ul>
</div>
<script>
// 获取无序列表元素
const oUL = document.querySelector('#users');
// 获取输入框元素
const oInput = document.getElementById('unDebounceInput');
// 创建一个防抖处理后的搜索函数,延迟时间为500毫秒
const debounceNameSearch = debounce(handleNameSearch, 500);
// 为输入框添加keyup事件监听器,当用户输入时触发防抖处理后的搜索函数
oInput.addEventListener('keyup', debounceNameSearch)
// 处理用户搜索的函数
function handleNameSearch(){
// 获取输入框的值,并去除前后空格
let value = oInput.value.trim();
// 如果输入框为空,清空无序列表的内容并返回
if (value == '') {
oUL.innerHTML = '';
return;
}
// 使用fetch向后端接口发送请求,获取用户数据
fetch('http://localhost:3001/users')
.then(res => res.json()) // 将响应转换为JSON格式
.then(users => {
// 使用filter方法筛选出名字包含输入值的用户
const filterUsers = users.filter(user => user.name.includes(value));
// 使用map方法将筛选后的用户数组转换为HTML字符串,并设置为无序列表的内容
oUL.innerHTML = filterUsers.map(user =>
`<li>${user.name}</li>`
).join("");
})
.catch(error => {
console.error('获取用户数据时出错:', error);
});
}
// 防抖函数
function debounce(fn, delay) {
let id; // 用于存储定时器ID
return function() {
// 清除之前的定时器
clearTimeout(id);
// 设置新的定时器
id = setTimeout(() => {
fn(); // 在延迟时间后调用传入的函数
}, delay);
}
}
</script>
</body>
</html>
分析
-
debounceNameSearch
是一个经过防抖处理的handleNameSearch
函数,防抖延迟为500毫秒。 -
为输入框添加了
keyup
事件监听器,当用户在输入框中输入内容时,会触发debounceNameSearch
函数。 -
防抖函数:
debounce
函数是一个高阶函数,接受一个函数fn
和一个延迟时间delay
作为参数。- 返回一个新的函数,当这个新函数被调用时,会清除之前的定时器,并设置一个新的定时器。
- 如果在
delay
时间内再次调用新函数,之前的定时器会被清除,新的定时器会被设置。 - 这样可以确保
fn
函数在用户停止输入delay
毫秒后才被调用,避免了频繁调用导致的性能问题。
运行结果
我们只需输入名字的第一个字然后便能查询到结果,可以看到我们从输入到得到结果只进行了两次网络请求。
有了防抖函数,妈妈再也不用担心我被上司炒鱿鱼了