显示的屏幕截图来自文章的模拟问题部分,而不是原始代码问题,由于隐私问题。 显示的屏幕截图来自文章的模拟问题部分,而不是原始代码问题,由于隐私问题。 ️ 内容表 设立 问题:页面在输入中冻结 失败的Debug尝试 突破:停止脚本执行 The Root Cause: A Loop That Never Ends 冰冻模拟(试试自己) 我学到的东西 奖金思维:调试记忆泄露 天天 设立 这个bug出现在一个 项目。 React + TypeScript + Redux + RxJS 表格有一个单一的数字字段 当更新时,它触发了 (使用构建 ) to recalculate the 国家合并文本。 quantity Redux selector reselect Total cost 一切看起来都很好,在 侧面。 Buy 但是,转向 页面造成了一些奇怪的事情:页面在进入时即刻冻结 . Sell 1 问题:页面在输入中冻结 在量域中键入时: The UI froze completely The browser tab became unresponsive The in Chrome Performance Monitor. (Sometimes, the JS heap size also keeps increasing) CPU usage 100% 这不是一个典型的“慢”渲染。 . 完整吊 Chrome 最终显示了“页面不响应”对话框,我不得不杀死标签。 失败的Debug尝试 常见的调试方法没有帮助: Attempt Result console.log Never printed anything debugger; Too slow or never triggered React DevTools Profiler Froze with the app Chrome Performance Profiler Couldn’t finish recording Removing components Still froze, even with just the input console.log 从不打印任何东西 debugger; 太慢或从未触发 反应 DevTools 配置文件 用 app 冻结 Chrome 性能配置文件 无法完成录音 删除组件 仍然冻结,即使只有输入 The issue had to be a 无穷无尽,但在哪里? loop or recursive render 突破:停止脚本执行 然后我意识到:如果JavaScript堆积不断增长, . JavaScript is still running 所以我打开 使用隐藏的宝石: Chrome DevTools → Sources tab Pause Script Execution (⏸️) 不幸的是,我甚至在官方的Chrome DevTools文件中也看不到这个功能的解释: https://developer.chrome.com/docs/devtools/javascript/breakpoint 不幸的是,我甚至在官方的Chrome DevTools文件中也看不到这个功能的解释: https://developer.chrome.com/docs/devtools/javascript/breakpoint https://developer.chrome.com/docs/devtools/javascript/breakpoint 步骤: Open Chrome DevTools first! You won’t be able to open them during the freeze. Reproduce the freeze (enter quantity). When the tab hangs, open . DevTools → Sources tab Click the icon (top-right). ⏸️ Pause Chrome freezes JS execution . at that exact line Scroll down on the right panel & check the panel to trace which functions are currently executing. Call Stack Scroll through the parent calls to reveal how the function chain started. You can even click on the parent calls to see their invoked line! The Root Cause: A Loop That Never Ends 暂停的堆栈揭示了由 8 个 + 函数组成的链,从 处理,并在A内部结束 使用 A . onChange utility function Redux Reselect selector 这里是罪魁祸首: let a = 0; const size = props.size; // expected number, got string while (a < size) { // do something } 变成外 间接来自输入值:a 如 . props.size string "5" 由于JS的强迫奇怪,循环比较在某些条件下未能退出,导致无限循环并冻结整个线程。 修复它就像在使用前将值转换为数字一样简单: const size = Number(props.size); 很快,网页冻结就消失了。 冰冻模拟(试试自己) 您可以重建这个精确的错误,并通过访问此代码沙盒来尝试调试技巧。 或在新的代码中运行下面的代码 但先把你的工作保存下来,因为这 打开你的浏览器 链接 Create React App, 威尔 链接 import { useState } from "react"; export default function App() { const [quantity, setQuantity] = useState(""); const handleChange = (e) => { const value = e.target.value; setQuantity(value); const end = Date.now() + 145000; let a = 0; // ❌ Intentional infinite loop while (Date.now() < end) { // Busy-wait a++; } console.log("Done!"); // never reached }; return ( <div style={{ padding: 20 }}> <h2>🧊 Simulate a Page Freeze</h2> <input type="text" placeholder="Enter quantity" value={quantity} onChange={handleChange} /> <p>Type any number and watch Chrome suffer.</p> </div> ); } 复制的步骤 打开此代码在上面的 codesandbox 或本地。 在输入中输入任何数字。 观察冰冻坚固的标签。 Open . Chrome DevTools → Sources tab → ⏸️ Pause script execution 观察调用堆栈中的 handleChange 内部的无限循环。 我学到的东西 当没有什么工作时:停止脚本执行是银子子弹。 无限的循环可以隐藏在选择器,减速器或实用文件中,远离用户界面。 在计算之前始终清洁和检查用户输入。 虽然循环是尖锐的工具:一个错误的条件,你的应用程序会成为一个CPU烘焙机。 奖金思维:调试记忆泄露 同样的技术可以帮助追踪慢 →JS堆积逐渐增加的情况。 memory leaks 在空闲时间中暂停脚本执行可能会显示哪些背景流程或订阅仍在不必要地运行。 但这是另一个文章的实验 😉。