如何解构JSON文件并在站点展示内容?加载大量对象致Chrome崩溃
解决大量JSON数据加载导致浏览器崩溃的问题
问题根源
你当前的代码在循环里每次都执行con.innerHTML += ...,这会频繁触发浏览器的DOM重排与重绘,当数据量达到数千条时,主线程被持续阻塞,最终导致浏览器崩溃。
解决方案1:批量插入DOM,减少重绘次数
把所有元素先组装到文档片段或者字符串中,一次性插入DOM,避免频繁修改页面结构。
方案1.1 使用DocumentFragment(推荐,性能更优)
function info(x){ const fragment = document.createDocumentFragment(); x.messages.forEach(element => { const p = document.createElement('p'); p.textContent = `${element.creator.name}: ${element.text}`; fragment.appendChild(p); }); con.appendChild(fragment); }
方案1.2 拼接HTML字符串后一次性赋值
function info(x){ let htmlStr = ''; x.messages.forEach(element => { htmlStr += `<p>${element.creator.name}: ${element.text}</p>`; }); con.innerHTML = htmlStr; // 一次性替换,而非累加 }
解决方案2:分批渲染+空闲执行
把数据拆分成小批次,利用浏览器空闲时间逐步渲染,避免主线程长时间被占用。
async function getData(){ const response = await fetch(url); const data = await response.json(); const batchSize = 50; // 每批渲染50条,可根据性能调整 let currentIndex = 0; function renderNextBatch(){ const endIndex = Math.min(currentIndex + batchSize, data.messages.length); const fragment = document.createDocumentFragment(); for(let i = currentIndex; i < endIndex; i++){ const element = data.messages[i]; const p = document.createElement('p'); p.textContent = `${element.creator.name}: ${element.text}`; fragment.appendChild(p); } con.appendChild(fragment); currentIndex = endIndex; // 还有未渲染的数据,就放到浏览器空闲时继续 if(currentIndex < data.messages.length){ requestIdleCallback(renderNextBatch); // 兼容性不好的话可以用 setTimeout(renderNextBatch, 0) } } renderNextBatch(); }
解决方案3:虚拟滚动(处理超大量数据最优)
只渲染当前视口内的内容,当用户滚动时动态加载/替换可见区域的数据,彻底避免一次性渲染数千条DOM的问题。核心思路是监听滚动事件,计算可见区域范围,只渲染对应范围内的数据。
简化版示例:
async function getData(){ const response = await fetch(url); const data = await response.json(); const messages = data.messages; const container = con; const itemHeight = 20; // 假设每条消息高度固定为20px container.style.height = `${messages.length * itemHeight}px`; // 设置容器总高度 // 监听滚动事件,渲染可见区域的消息 container.addEventListener('scroll', () => { const scrollTop = container.scrollTop; const visibleStart = Math.floor(scrollTop / itemHeight); const visibleEnd = Math.min(visibleStart + 50, messages.length); // 渲染当前视口+额外50条避免空白 // 清空当前可见区域外的内容,只保留可见部分 container.innerHTML = ''; const fragment = document.createDocumentFragment(); for(let i = visibleStart; i < visibleEnd; i++){ const element = messages[i]; const p = document.createElement('p'); p.textContent = `${element.creator.name}: ${element.text}`; p.style.position = 'absolute'; p.style.top = `${i * itemHeight}px`; fragment.appendChild(p); } container.appendChild(fragment); }); // 初始渲染第一屏 container.dispatchEvent(new Event('scroll')); }
额外注意事项
- 优先使用
textContent而非HTML字符串拼接,避免潜在的XSS风险(如果JSON数据包含用户输入内容)。 - 避免在循环中直接操作DOM,任何DOM操作都应该尽量批量执行。
内容的提问来源于stack exchange,提问作者Preetham
相关产品推荐
相关产品推荐

