<object> 标签本身不泄漏,但加载的插件、嵌入文档或 Blob URL 会持续持有资源;必须显式调用 URL.revokeObjectURL()、pdfDoc.destroy() 等销毁接口,并在设空 data 后等待微任务再移除 DOM。

<object> 标签本身不泄漏,但加载的插件、嵌入文档(如 PDF、SWF、自定义 MIME 类型)或通过 data 属性引用的 Blob/URL 会持续持有资源;不主动销毁,浏览器不会自动释放其内部上下文、渲染缓冲区或 JS 执行环境。
object.data 指向 blob URL 时必须 revokeObjectURL
用 URL.createObjectURL(blob) 赋给 object.data 后,Blob 数据会常驻内存,直到显式调用 URL.revokeObjectURL()。若反复创建新 URL 却不清理旧的,内存阶梯式上涨。
- 每次设置前先检查并清理旧 URL:
if (obj.data && obj.data.startsWith('blob:')) URL.revokeObjectURL(obj.data) - 不能只在组件卸载时 revoke —— 若中间切换过多次 data,只 revoke 最后一个没用;应在每次更新前 revoke 上一个
- Firefox 对未 revoke 的 blob URL 更敏感,可能卡住整个进程;Chrome 会在页面关闭时兜底,但不可依赖
object 加载第三方插件(如 PDF.js、旧版 Acrobat 插件)后无法靠 remove() 清理
obj.remove() 或 parent.innerHTML = '' 只删 DOM,插件实例仍在后台运行,尤其 PDF.js 创建的 PDFDocumentLoadingTask 和渲染 canvas 会滞留。
- 若使用 PDF.js,必须调用
pdfDoc?.destroy()(返回 Promise),且等待 resolve 后再移除 DOM - 对老式 NPAPI 插件(已淘汰但仍有内网系统在用),需先设
obj.data = 'about:blank'触发插件卸载,再setTimeout(() => obj.remove(), 0) - 避免在
object上直接绑定事件监听器(如load、error)后不清理:卸载时务必obj.removeEventListener('load', handler)
object.contentDocument / contentWindow 引用导致 Detached DOM tree
当 object 加载 HTML 文档(如 data="iframe-like.html"),其 contentDocument 是独立上下文;若该文档里绑了定时器、监听器或闭包引用了父页对象,卸载后会形成 Detached HTMLDocument + Detached HTMLDivElement 链。
立即学习“前端免费学习笔记(深入)”;
- 不要直接访问
obj.contentDocument并缓存到全局变量或类字段中 - 若必须操作子文档,确保所有事件监听器都用
{ signal: controller.signal }绑定,并在父组件卸载时controller.abort() - 加载完成后,可用
obj.addEventListener('load', () => { /* 在这里清理子文档里的定时器 */ }, { once: true }),但前提是子文档 JS 配合暴露清理入口
真正难防的不是 <object> 标签本身,而是它背后加载的“黑盒”——你无法控制 PDF.js 内部是否清空了 WebGL 纹理,也无法确认旧插件是否响应 data = about:blank。所以关键动作永远是:设空 data → 等待微任务 → 主动调用已知销毁接口 → 最后移除 DOM。



















