JS新手求助:如何加快基于window.onload生成页面目录的速度?
Hey there! As someone who’s wrestled with slow DOM-ready scripts early on, let’s break down how to speed up your table of contents generation—great question for a JS/jQuery newbie, this is such a common optimization hurdle!
1. 用DOMContentLoaded代替window.onload
The biggest culprit here is window.onload: it waits for every single resource on the page to finish loading—images, stylesheets, external scripts, everything. That’s why your script feels slow to run.
document.onload isn’t a standard browser event (which is why switching to it did nothing). Instead, use DOMContentLoaded: it fires the moment the HTML is parsed and the DOM structure is ready, no need to wait for non-critical resources like images.
Here’s how to swap it in:
document.addEventListener('DOMContentLoaded', function() { // Your TOC generation code goes here });
2. 别用正则处理HTML字符串——直接遍历DOM元素
Your current code uses a regex to rewrite the entire innerHTML of your content section. This is both slow (parsing huge strings is inefficient) and fragile (regex can break if your <h2>/<h3> tags have extra attributes or nested elements like <span>).
Instead, directly select and iterate over heading elements—this is faster and way more reliable:
const headings = document.querySelectorAll('h2, h3'); // Grab only the levels you care about const maxLevel = 3; let currentLevel = 0; const tocFragment = document.createDocumentFragment(); let currentList = null; headings.forEach(heading => { const level = parseInt(heading.tagName.charAt(1)); if (level > maxLevel) return; // Create anchor for the heading (use id instead of outdated name attribute) const anchorId = heading.textContent.replace(/[^a-zA-Z]+/g, '-'); heading.setAttribute('id', anchorId); // Keep your offset fix for anchor scrolling heading.style.paddingTop = '60px'; heading.style.marginTop = '-60px'; // Build TOC list structure if (level > currentLevel) { // Add a nested list const newList = document.createElement('ol'); currentList ? currentList.lastElementChild.appendChild(newList) : tocFragment.appendChild(newList); currentList = newList; } else if (level < currentLevel) { // Move up to parent lists for (let i = 0; i < currentLevel - level; i++) { currentList = currentList.parentElement.parentElement; } } // Add list item with link const listItem = document.createElement('li'); const link = document.createElement('a'); link.href = `#${anchorId}`; link.textContent = heading.textContent; listItem.appendChild(link); currentList.appendChild(listItem); currentLevel = level; }); // Append the fully built TOC to the page document.getElementById('toc').appendChild(tocFragment);
3. 用DocumentFragment减少DOM重绘
Every time you modify the DOM (like using innerHTML +=), the browser has to re-render parts of the page—this is called a reflow, and it’s expensive. DocumentFragment lets you build all your TOC elements off-screen first, then insert them all at once. This cuts down on reflows drastically and makes your script run much faster.
4. 缓存DOM元素引用
Instead of calling document.getElementById('contents') or document.getElementById('toc') multiple times, store them in variables at the start of your script. This saves the browser from searching the entire DOM every time you need the element:
const contentsEl = document.getElementById('contents'); const tocEl = document.getElementById('toc'); // Now use contentsEl and tocEl instead of re-querying
为什么你的原 code felt slow?
window.onloadwaits for all resources, not just the DOM structure- Regex replacement on large
innerHTMLstrings is slow and error-prone - Multiple small DOM modifications (each
innerHTML +=triggers a reflow)
Putting all these tweaks together will make your TOC load noticeably faster, even on pages with lots of headings.
内容的提问来源于stack exchange,提问作者Ujjawal Bhandari

