
关掉一个面板,画面消失了,摄像头指示灯却还亮着。把组件从 DOM 移除,不会自动取消 RAF、停止 MediaStreamTrack 或释放自己创建的音频节点。资源需要可核对的所有权。
每根“线”都写清谁负责拔
把资源分成自有与借用两类。自建 track、节点、Worker 和监听器由本模块清理;共享 AudioContext、应用级播放器则交还拥有者。暂停是暂时停止工作,销毁是终止本模块的生命周期,不能共用一个布尔变量糊过去。
下方 Scope 记录成对的 pause/resume 与 dispose,销毁按后进先出执行,允许依赖资源先卸载。一个清理失败不妨碍后续清理,但错误会汇总抛出,不静默吞掉。这里测试资源是计数器,没有打开硬件。
class ResourceScope {
constructor(){this.state='active';this.items=[];}
own(resource){
if(this.state==='disposed')throw Error('disposed');
if(typeof resource.dispose!=='function')throw Error('dispose required');
this.items.push(resource);
if(this.state==='paused')resource.pause?.();
return resource;
}
pause(){
if(this.state!=='active')return;
this.state='paused';const errors=[];
for(const r of this.items)try{r.pause?.();}catch(e){errors.push(e);}
if(errors.length)throw new AggregateError(errors,'pause');
}
resume(){
if(this.state!=='paused')return;
this.state='active';const errors=[];
for(const r of this.items)try{r.resume?.();}catch(e){errors.push(e);}
if(errors.length)throw new AggregateError(errors,'resume');
}
dispose(){
if(this.state==='disposed')return;
this.state='disposed';const errors=[];
for(const r of this.items.reverse())try{r.dispose();}catch(e){errors.push(e);}
this.items=[];
if(errors.length)throw new AggregateError(errors,'dispose');
}
}

图中的 DISPOSED 没有返回箭头。需要再次工作时创建新实例,不复活半销毁对象。暂停失败时 Scope 仍标为 paused,但资源可能存在部分失败;调用方应展示错误并选择销毁,不宣称暂停已全部成功。
浏览器适配器怎么接
RAF 适配器保存当前句柄,pause/dispose 都取消,resume 只启动一条循环。事件监听器适配器保存相同的函数引用及 capture 选项,dispose 调用 removeEventListener。专属摄像头 track 在 dispose 中 stop;借用 track 不应被任意关闭。
音频节点应记录连接关系并 disconnect;计划启动的 AudioScheduledSourceNode 要停止,已结束的节点要释放引用。暂停共享 AudioContext 会影响其他模块,因此不要把 context.suspend 当成某个面板的通用 pause。Worker 同样需要区分共享与专属。
本轮构造测试检查了清理顺序、幂等销毁、暂停恢复和错误后继续清理。没有真实摄像头、声音输出或内存剖析结果。浏览器验收需要反复挂载/卸载,检查活跃 track、RAF 和监听器数量,并观察指示灯及残留声音;一次页面刷新后内存下降不能证明模块清理正确。
复现记录
本轮在 Node.js v26.3.0 中运行随文核心逻辑的构造样例,进程退出码为 0。测试输出:
PASS: pause/resume, reverse cleanup, error aggregation, idempotent dispose, ownership after disposal rejected
将上方完整代码保存为 example.mjs,以 Node.js 26 执行 node example.mjs 可加载核心与教学输入;函数默认不访问网络、模型或硬件。浏览器适配入口需要明确传入对应对象,本轮未执行这些入口。上面的通过项来自独立构造样例,不能替代集成测试。
资料与时效
- Web Audio API 1.1:2026-09-22。
- Hand landmarks detection guide for Web:首次发布日期未核实;更新 2026-08-17。
本稿对应原预排时段;实际发布前须人工复核来源更正、SDK/API 版本及可用性,不据此预言 10 月 24–31 日的新事件。
本文聚焦前端音视频模块中 MediaStreamTrack、Web Audio API 节点、RAF 和事件监听器等资源的创建、暂停与销毁机制,强调所有权划分、清理顺序、幂等性及错误处理。提出按‘自有/借用’分类管理资源,禁止复用半销毁对象,并通过 Scope 实现后进先出的可靠释放。内容涵盖浏览器适配要点与测试验证方法,不涉及硬件实测,但强调指示灯、内存残留等验收指标。

51

被折叠的 条评论
为什么被折叠?



