应优先用 settimeout 递归替代 setinterval 轮询,确保每次请求完成后再发起下一次,避免请求堆积、卡顿和后端限流;同时需动态拼接时间戳防缓存、用 dompurify 过滤 html、粒度更新 dom、页面卸载时清除定时器并 abort fetch 请求。

用 setInterval 轮询获取新内容,但别直接写死 URL
新手常把 fetch 写在 setInterval 里就以为能自动刷新,结果页面卡顿、请求堆积、甚至被后端限流。关键不是“能不能刷”,而是“怎么刷才不崩”。轮询前先确认后端是否支持无状态的 GET 接口(比如 /api/status),且返回数据结构稳定(字段名不变、不带 session 依赖)。避免轮询登录态接口或需要 CSRF token 的路径。
实操建议:
- 用
setTimeout替代setInterval,每次请求完成后再设下一次——防止请求未返回就发起新请求 - 加个简单防抖:连续失败 3 次后暂停轮询,用
clearTimeout和计数器控制 - URL 动态拼接时间戳参数(如
?t=${Date.now()})绕过浏览器缓存,但别用Math.random(),容易触发 CSP 策略拦截
DOM 更新别直接 innerHTML = data,小心 XSS 和重绘开销
拿到新内容后,如果直接 document.getElementById('list').innerHTML = response.data,既可能执行恶意脚本(后端没过滤时),又会让整个列表重排重绘,滚动位置丢失。尤其当新数据只改了某一行,全量替换太粗暴。
实操建议:
- 用
textContent渲染纯文本字段;含 HTML 的字段必须用 DOMPurify 过滤(DOMPurify.sanitize(html)),别信正则替换 - 对比前后数据 ID 列表,只增删改对应
<li>元素,用insertBefore、removeChild控制粒度 - 更新前保存当前滚动位置(
scrollTop),更新后尝试恢复,但要加requestAnimationFrame延迟执行,避免 layout thrashing
页面卸载时必须清除定时器,否则内存泄漏静默发生
用户切到其他标签页或关闭页面时,setInterval 或未清理的 setTimeout 仍可能运行,持续发请求、占内存、甚至报错 Cannot read property 'appendChild' of null。这不是“偶尔出错”,是必然发生的资源泄漏。
实操建议:
- 把定时器 ID 存在全局变量(如
window.refreshTimer),在beforeunload事件里调用clearTimeout(window.refreshTimer) - 更稳妥的做法:用
AbortController配合fetch,在卸载前调controller.abort(),避免请求发出去却没人处理响应 - 不要依赖
visibilitychange事件来暂停轮询——部分浏览器在后台标签页会降频执行 JS,但不保证停止,仍需手动清理
本地测试时用 localhost,别用 file:// 协议
file:// 协议下,fetch 默认被浏览器禁止(CORS 错误:Failed to fetch),新手常卡在这一步,以为代码写错了。这不是 bug,是安全策略。
实操建议:
- 用 Python 快速起一个静态服务:
python3 -m http.server 8000,然后访问http://localhost:8000/your-page.html - Chrome 启动时加参数
--disable-web-security --user-data-dir=/tmp/test仅用于调试,切勿长期使用 - 后端接口若还没写好,可用
mock-service-worker拦截请求并返回模拟 JSON,避免依赖真实服务器
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











