切换Forge Viewer模型后重新加载扩展遇问题求助
ng2-adsk-forge-viewer切换模型时扩展卸载触发遍历错误的解决方法
问题背景
基于ng2-adsk-forge-viewer封装Angular Viewer应用,已完成Viewer搭建并加载DataVisualisation SDK的多个扩展,但切换模型时扩展会被卸载并触发错误,报错点位于遍历扩展实例的循环处。
触发模型切换的代码:
// Updates the model to be displayed in the viewer public triggerDocumentChange() { this.modelService.selectedModelUrn = this.selectedModel.urn; this.viewerComponent.DocumentId = this.urnify(this.selectedModel.urn); }
尝试的解决步骤(触发错误的代码):
this.viewer.addEventListener( Autodesk.Viewing.GEOMETRY_LOADED_EVENT, async () => { // Initialize our data view with the modelService to help change the sensor values const dataView = new MyDataView(this.modelService, this.viewer); await dataView.init({ start: new Date("2022-01-01"), end: new Date("2022-01-30"), }); this.reRegisterAndLoadExtensions(); // Get the instance of the registered extensions from the viewer const extensions = this.getExtensionsInstance(); for (const ext of extensions) { // 错误触发位置 console.log("Loaded extension: " + ext); ext.dataView = dataView; ext.activate(); } });
错误原因分析
- 切换模型时,Viewer会自动卸载当前所有已加载的扩展,
reRegisterAndLoadExtensions()执行后,扩展加载是异步操作,直接同步遍历会拿到未初始化/无效的扩展实例,导致赋值或调用方法时报错。 GEOMETRY_LOADED_EVENT可能在模型加载流程中多次触发,若未处理扩展实例的重复初始化,会导致实例状态混乱。getExtensionsInstance()返回的数组可能包含undefined或非扩展对象,遍历直接操作会触发类型错误。
解决方案
方案1:异步等待扩展加载完成后再遍历
修改代码,确保扩展加载完成后再获取有效实例并操作:
this.viewer.addEventListener( Autodesk.Viewing.GEOMETRY_LOADED_EVENT, async () => { const dataView = new MyDataView(this.modelService, this.viewer); await dataView.init({ start: new Date("2022-01-01"), end: new Date("2022-01-30"), }); // 等待所有扩展注册并加载完成 await this.reRegisterAndLoadExtensions(); // 获取已加载的扩展实例并过滤无效项 const extensions = this.getExtensionsInstance(); const validExtensions = extensions.filter(ext => ext && typeof ext.activate === 'function'); for (const ext of validExtensions) { console.log("Loaded extension: " + ext.extensionId); ext.dataView = dataView; ext.activate(); } }); // 重构reRegisterAndLoadExtensions为异步函数 async reRegisterAndLoadExtensions(): Promise<void> { // 替换为你的扩展ID列表 const extensionIds = ['DataVisualisationExtension', 'YourCustomExt1', 'YourCustomExt2']; for (const id of extensionIds) { // 先卸载旧实例避免冲突 if (this.viewer.getExtension(id)) { this.viewer.unloadExtension(id); } // 异步加载扩展,确保加载完成再处理下一个 await this.viewer.loadExtension(id); } }
方案2:监听扩展加载完成事件逐个处理
改用Autodesk.Viewing.EXTENSION_LOADED_EVENT监听每个扩展的加载完成,避免同步遍历的时机问题:
// 组件内存储当前dataView实例 private currentDataView: MyDataView | null = null; this.viewer.addEventListener( Autodesk.Viewing.GEOMETRY_LOADED_EVENT, async () => { this.currentDataView = new MyDataView(this.modelService, this.viewer); await this.currentDataView.init({ start: new Date("2022-01-01"), end: new Date("2022-01-30"), }); // 先卸载所有旧扩展清理状态 const loadedExts = this.viewer.getLoadedExtensions(); loadedExts.forEach(ext => this.viewer.unloadExtension(ext.extensionId)); // 重新加载扩展 this.reRegisterAndLoadExtensions(); }); // 监听单个扩展加载完成事件 this.viewer.addEventListener(Autodesk.Viewing.EXTENSION_LOADED_EVENT, (event) => { const ext = event.extension; if (this.currentDataView && ext) { ext.dataView = this.currentDataView; ext.activate(); console.log("Loaded extension: " + ext.extensionId); } });
关键注意事项
- 切换模型前必须卸载所有已加载的扩展,避免内存泄漏和实例冲突。
- 扩展加载是异步操作,必须等待加载完成后再进行实例赋值或方法调用。
- 始终过滤无效扩展实例,避免遍历到
undefined或非扩展对象导致的报错。
内容的提问来源于stack exchange,提问作者Merrick
相关产品推荐
相关产品推荐

