You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

切换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(); 
    } 
}); 

错误原因分析

  1. 切换模型时,Viewer会自动卸载当前所有已加载的扩展,reRegisterAndLoadExtensions()执行后,扩展加载是异步操作,直接同步遍历会拿到未初始化/无效的扩展实例,导致赋值或调用方法时报错。
  2. GEOMETRY_LOADED_EVENT可能在模型加载流程中多次触发,若未处理扩展实例的重复初始化,会导致实例状态混乱。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 11:37:08