处理大文本时JavaScript程序冻结并引发页面刷新问题求助
Hey there! Awesome job building this web tool as a high schooler—especially with your Java background transitioning to JavaScript. Let's tackle that frustrating freeze and page refresh problem you're seeing with large texts.
What's Causing the Problem?
Let's break down the key issues in your code:
- Infinite Loop Bug: The line
for(a = i- 25; a <= a + 40; a++)creates an infinite loop—a <= a +40is always true! This will immediately lock up your browser, which often leads to a forced page refresh. - Heavy Main Thread Blocking: JavaScript runs on a single main thread, and your triple nested loops (over input words, keywords, then surrounding words) will grind things to a halt with large text inputs.
- Inefficient String Concatenation: Repeatedly doing
found = found + input[a]creates tons of new string objects, which adds unnecessary performance overhead.
Fixed & Optimized Code
Here's the revised version with fixes and improvements:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <textarea id="input" rows="8" cols="100" placeholder="Paste your large text here"></textarea><br/> <textarea id="keywords" rows="1" cols="50" placeholder="Enter keywords separated by spaces"></textarea><br/> <textarea id="output" rows="8" cols="100" readonly></textarea><br/> <button id="read">READ!</button><br /> <script type="text/javascript"> document.getElementById('read').onclick = function(event) { // Get and clean input values const inputText = document.getElementById('input').value.trim(); const keywordText = document.getElementById('keywords').value.trim(); // Handle empty inputs to avoid unnecessary processing if (!inputText || !keywordText) { alert("Please enter both text and keywords!"); return; } const inputWords = inputText.split(" "); // Pre-convert keywords to lowercase once (optimization) const keywords = keywordText.split(" ").map(k => k.toLowerCase()); // Use an array to collect results (way more efficient than string concatenation) const foundSegments = []; for (let i = 0; i < inputWords.length; i++) { const currentWord = inputWords[i].toLowerCase(); // Check if current word matches any keyword (exits early when a match is found) const matchesKeyword = keywords.some(keyword => currentWord.includes(keyword)); if (matchesKeyword) { // Calculate valid start and end indices to avoid array out-of-bounds errors const startIdx = Math.max(0, i - 25); const endIdx = Math.min(inputWords.length - 1, i + 40); // Extract the segment and join with spaces (since we split by spaces earlier) const segment = inputWords.slice(startIdx, endIdx + 1).join(" "); foundSegments.push(segment); } } // Join all segments with newlines and set to output document.getElementById('output').value = foundSegments.join("\n\n"); } </script> </head> <body> </body> </html>
Key Improvements Explained
- Fixed the Infinite Loop: We now calculate valid
startIdxandendIdxusingMath.max/Math.minto stay within array bounds, then useslice()to grab the segment in one go (no messy nested loop for collecting words). - Optimized Keyword Checks: We convert all keywords to lowercase once upfront, instead of doing it every time in the loop. We also use
Array.some()to exit early when a keyword match is found. - Efficient Result Collection: Using an array (
foundSegments) to store results and joining it once at the end is way faster than repeated string concatenation—especially with large datasets. - Input Validation: Added checks for empty inputs to avoid running unnecessary code and alert the user.
- Readonly Output: Marked the output textarea as readonly so users can't accidentally edit the results.
Bonus: Handling Even Larger Texts
If you're working with really huge texts (like 100k+ words), the main thread might still block a bit. For that, you could use chunked processing with requestIdleCallback to split the work into smaller pieces and keep the page responsive. Let me know if you want to dive into that!
Great work getting this far—keep experimenting with JavaScript, you're off to a solid start!
内容的提问来源于stack exchange,提问作者BigCode232

