点击触发setTimeout后CPU占用飙升的原因及替代方案咨询
问题:点击触发新闻更新脚本后CPU占用飙升的排查与优化
问题场景
一段用于更新网站新闻板块的脚本功能正常,但点击触发后CPU瞬间占用率达40%,排查后定位到setTimeout的问题,各浏览器均存在此情况。
原脚本代码
function read_chat_adm(id_news) { var currentFileSize = 0; function updateFileContent_adm() { $.ajax({ url: 'read_news_adm.php?id_n=' + id_news, cache: false, success: function(data) { var fileSize = data.length; if (currentFileSize !== fileSize) { $('#news_adm_read').html(data); currentFileSize = fileSize; } }, complete: function() { setTimeout(updateFileContent_adm(), 5000); } }); } updateFileContent_adm(); }
调用方式
<div id="news_adm_read"></div> <span onclick="read_chat_adm('1235659845');">Load News</span>
问题根源
核心错误是setTimeout的调用方式:你直接执行了updateFileContent_adm()并把返回值传给setTimeout,而非传入函数引用。这会导致函数无延迟递归调用,瞬间被无限执行,直接拉满CPU。正确写法应该是传入函数本身(不带括号),让setTimeout在指定延迟后再执行函数。
优化方案
1. 修复setTimeout调用错误
这是最关键的修复,把带括号的函数执行改为传入函数引用:
complete: function() { setTimeout(updateFileContent_adm, 5000); // 去掉括号,传入函数本身 }
2. 防止重复轮询与终止无效请求
如果用户多次点击"Load News",会启动多个轮询实例,加剧资源占用。添加标记控制轮询状态,同时终止未完成的旧请求:
function read_chat_adm(id_news) { var currentFileSize = 0; var timerId = null; // 存储定时器ID var xhr = null; // 存储AJAX请求实例 function updateFileContent_adm() { // 终止未完成的旧请求 if (xhr && xhr.readyState !== 4) { xhr.abort(); } xhr = $.ajax({ url: 'read_news_adm.php?id_n=' + id_news, cache: false, success: function(data) { var fileSize = data.length; if (currentFileSize !== fileSize) { $('#news_adm_read').html(data); currentFileSize = fileSize; } }, complete: function() { timerId = setTimeout(updateFileContent_adm, 5000); } }); } // 清除已有定时器,避免重复启动轮询 if (timerId) { clearTimeout(timerId); } updateFileContent_adm(); }
3. 替换轮询为主动推送(可选)
如果新闻更新频繁,轮询会持续消耗资源。可以改用Server-Sent Events(SSE) 或WebSocket,由服务器主动推送更新,彻底避免客户端频繁发起请求:
- SSE适合单向消息推送,实现简单,兼容大部分现代浏览器;
- WebSocket支持双向通信,功能更强大,但实现复杂度稍高。
4. 优化DOM更新逻辑
不要每次都用html(data)替换整个板块,对比新旧内容后只更新变化部分,减少DOM操作开销:
success: function(data) { var $target = $('#news_adm_read'); if ($target.html() !== data) { $target.html(data); } }
内容的提问来源于stack exchange,提问作者Jean
相关产品推荐
相关产品推荐

