如何优化JS+HTML海量数据场景下的搜索性能?
搜索功能性能优化问题
当前代码可在HTML页面生成容器并实现搜索匹配显示/隐藏功能,但当数据量达到2000条及以上时,搜索操作会出现5-10秒的卡顿,需要优化搜索算法提升速度。
原实现代码
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div class="emotes_area" id="emotes_area"> </div> <input class="search_input" id="input_search" type="text" placeholder="Search Something..."> </body> </html>
CSS
.emotes_area{ position: absolute; width: 404px; height: 703px; top: 165px; left: 62px; flex-wrap: wrap; overflow-y: auto; overflow-x: hidden; } .emotes_area::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.25); background-color: rgba(255, 255, 255, 0.25); } .emotes_area::-webkit-scrollbar { width: 1px; background-color: #00000000; } .emotes_area::-webkit-scrollbar-thumb { -webkit-box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.25); background-color: rgb(255, 255, 255); } .emote_container{ position: relative; width: 123px; height: 131px; flex-shrink: 0; background: radial-gradient(82.29% 82.29% at 50% 50%, rgba(143, 143, 143, 0.5) 10%, rgba(255, 255, 255, 0.00) 90%); box-shadow: inset 0 0 0 1px #81818173; display: flex; top: 0px; cursor: pointer; margin: 2.7px; } /* New CSS */ .parent-container { display: flex; flex-wrap: wrap; } .child { max-width: 33.33%; }
JavaScript
document.addEventListener("DOMContentLoaded", function () { var count = 0; var countOuter =0; var table=document.createElement("div"); table.classList.add("parent-container") for(var i=0;i<(200);i++){ //SATIR var tr=document.createElement("div"); tr.classList.add("child", "childno") tr.classList.add(countOuter) table.appendChild(tr); tr.innerHTML= '<div id="'+count+'" class="emote_container">'+ '<span id="'+count+'" class="emote_name_lbl"> '+count+' </span>'+ '</div>'; count++; countOuter++; } document.getElementById("emotes_area").innerHTML=""; document.getElementById("emotes_area").appendChild(table); }); document.getElementById("input_search").addEventListener("input", function() { var searchValue = this.value.toLowerCase(); // Get the lowercase value of the input var emoteContainers = document.getElementsByClassName("child"); for (var i = 0; i < emoteContainers.length; i++) { var emoteName = emoteContainers[i].getElementsByClassName("emote_name_lbl")[0].innerText.toLowerCase(); if (emoteName.includes(searchValue)) { emoteContainers[i].style.display = "flex"; // Show the emote container } else { emoteContainers[i].style.display = "none"; // Hide the emote container } } });
优化方案
1. 提前缓存数据,避免重复DOM查询
原代码每次搜索都要反复查询DOM元素,这是卡顿的核心原因。初始化时把每个表情的DOM元素和名称缓存到数组里,后续搜索直接遍历数组即可。
修改后的初始化代码:
let emoteData = []; // 全局缓存数组,存储元素与对应名称 document.addEventListener("DOMContentLoaded", function () { let count = 0; const table = document.createElement("div"); table.classList.add("parent-container"); const fragment = document.createDocumentFragment(); // 用文档片段减少DOM重排 for(let i=0;i<2000;i++){ const tr = document.createElement("div"); tr.classList.add("child", "childno"); tr.innerHTML = ` <div id="${count}" class="emote_container"> <span id="${count}" class="emote_name_lbl"> ${count} </span> </div> `; fragment.appendChild(tr); // 缓存当前元素和小写名称,避免后续重复查询 emoteData.push({ element: tr, name: `${count}`.toLowerCase() }); count++; } table.appendChild(fragment); // 一次性插入所有元素,减少DOM操作 document.getElementById("emotes_area").innerHTML = ""; document.getElementById("emotes_area").appendChild(table); });
2. 优化搜索事件,加入防抖减少触发频率
输入时每打一个字就触发一次搜索会造成不必要的性能浪费,加入防抖函数,等待输入停止一段时间后再执行搜索,同时直接遍历缓存数组操作元素。
修改后的搜索事件代码:
// 防抖函数:延迟执行,避免输入时频繁触发 function debounce(func, delay = 200) { let timer; return function(...args) { clearTimeout(timer); timer = setTimeout(() => func.apply(this, args), delay); }; } document.getElementById("input_search").addEventListener("input", debounce(function() { const searchValue = this.value.toLowerCase(); // 直接遍历缓存数组,跳过DOM查询 emoteData.forEach(item => { if (item.name.includes(searchValue)) { item.element.style.display = "flex"; } else { item.element.style.display = "none"; } }); }, 200));
3. 用CSS类切换显示状态(可选)
直接修改style.display不如切换CSS类高效,定义一个隐藏类,搜索时切换类即可:
/* 新增CSS类 */ .child.hidden { display: none !important; }
然后修改搜索逻辑:
emoteData.forEach(item => { if (item.name.includes(searchValue)) { item.element.classList.remove("hidden"); } else { item.element.classList.add("hidden"); } });
4. 避免使用动态HTMLCollection
原代码中getElementsByClassName返回的是动态集合,每次访问都会重新查询DOM,性能极低。换成querySelectorAll获取静态NodeList也能提升性能,但最优方案还是用前面的缓存数组。
内容的提问来源于stack exchange,提问作者Mehmet Akgün
相关产品推荐
相关产品推荐

