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

Delphi12+TMS WebCore登出清理内存重启报错解决方案咨询

Delphi 12 + TMS WebCore 登出重载页面时组件重名异常问题

背景

我用 Delphi 12 结合 TMS WebCore 开发了一款 Web 应用,在登出场景(用户主动操作或闲置超时触发)下,出于以下需求需要清理内存:

  • 安全考量
  • 规避未发现的内存泄漏问题
  • 允许浏览器下载应用新版本(若存在)

异常现象

但重启应用时持续抛出以下异常:

Error: Duplicate component name: "divHeading"
at Object.Create$1 (https://example.com.au/ops-test/ops_1_0_2109.js:3634:23)
at Object.CreateFmt (https://example.com.au/ops-test/ops_1_0_2109.js:3641:12)
at c.$create (https://example.com.au/ops-test/ops_1_0_2109.js:366:19)
at Object.ValidateRename (https://example.com.au/ops-test/ops_1_0_2109.js:15533:188)
at Object.SetName (https://example.com.au/ops-test/ops_1_0_2109.js:15513:21)
at Object.SetName (https://example.com.au/ops-test/ops_1_0_2109.js:33680:38)
at Object.LoadDFMValues (https://example.com.au/ops-test/ops_1_0_2109.js:127837:25)
at Object.CreateNewForm (https://example.com.au/ops-test/ops_1_0_2109.js:43375:13)
at Object.DoFormLoad (https://example.com.au/ops-test/ops_1_0_2109.js:43010:12)
at XMLHttpRequest.cb (https://example.com.au/ops-test/ops_1_0_2109.js:282:28)

需求

我希望实现以下任一目标:

  1. 阻止该异常发生(最优方案)
  2. 静默捕获异常并尝试再次重启

已尝试操作

试过多种方案,但主窗体构造函数仍持续抛出异常,说明上一会话的内存未被完全清理。

登出代码

procedure Tfrm_Ops_Main.Log_Out (AAuto : Boolean = False);
begin
  TConsole.Log (msg_Logging_Out);
  if AAuto
  then Stop_Warning_User_At_Tab_Close;
  Free_Child_Form;
  Close;
  { Allowing for Form to Close }
//  THtml.Replace_Page;
  THtml.Reload_After_Delay (400);
end;

尝试过的页面重载方法

  • Replace_Page
  • Reload_Page
  • Reload_Page_After_Delay

THtml 类代码

class procedure THtml.Replace_Page  (AUrl : string = '');
var
  lUrl  : string;
  lTime : Int64;
begin
  { Add time in ms if same URL }
  if AUrl = ''
  then begin
       LTime := Trunc ((Now - UnixEpoch) * ToMS);
       LUrl := window.location.href + '?t=' + IntToStr (LTime);
  end
  else LUrl := AUrl;
  document.location.replace (LUrl);
end;

class procedure THtml.Reload_Page;
begin
  document.location.reload (True);
end;

class procedure THtml.Reload_After_Delay (ADelayMS : Integer);
var
  LTimer : TWebTimer;
begin
  LTimer          := TWebTimer.Create(nil);
  LTimer.Interval := ADelayMS;
  LTimer.Enabled  := True;
  LTimer.OnTimer  := Do_Reload;
end;

class procedure THtml.Do_Reload (Sender : Tobject);
begin
  TWebTimer (Sender).Free;
  THtml.Reload_Page;
end;

解决方案

方案一:彻底清理组件引用(阻止异常最优解)

TMS WebCore 页面重载时,若之前的窗体/组件未完全销毁,会导致 DOM 元素或组件实例残留,触发重名异常。需在登出时确保所有组件引用被彻底释放:

  1. 完善窗体销毁逻辑
    在主窗体的 OnClose 事件中手动释放所有子组件、全局变量并解绑事件绑定:
procedure Tfrm_Ops_Main.FormClose(Sender: TObject; var Action: TCloseAction);
var
  I: Integer;
begin
  // 释放所有子窗体
  for I := Screen.FormCount - 1 downto 0 do
  begin
    if Screen.Forms[I] <> Self then
      Screen.Forms[I].Free;
  end;
  // 释放全局组件/变量(按需添加)
  if Assigned(GlobalCustomComponent) then
    GlobalCustomComponent.Free;
  // 解绑JS事件监听(按需添加)
  asm
    if window.appEventListeners {
      window.appEventListeners.forEach(item => {
        document.removeEventListener(item.event, item.handler);
      });
      window.appEventListeners = null;
    }
  end;
  Action := caFree;
end;
  1. 窗体销毁后立即重载
    延迟重载可能留下组件销毁的不确定窗口,建议在 OnDestroy 事件中直接触发重载:
procedure Tfrm_Ops_Main.FormDestroy(Sender: TObject);
begin
  THtml.Reload_Page;
end;

同时修改 Log_Out 方法,移除延迟逻辑:

procedure Tfrm_Ops_Main.Log_Out (AAuto : Boolean = False);
begin
  TConsole.Log (msg_Logging_Out);
  if AAuto then Stop_Warning_User_At_Tab_Close;
  Free_Child_Form;
  Close;
end;
  1. 优化缓存刷新逻辑
    使用 Replace_Page 时,用 JS 时间戳确保彻底绕过缓存:
class procedure THtml.Replace_Page  (AUrl : string = '');
var
  lUrl  : string;
  lTime : string;
begin
  if AUrl = '' then
  begin
    asm
      lTime = Date.now().toString();
    end;
    LUrl := window.location.origin + window.location.pathname + '?t=' + lTime;
  end
  else
    LUrl := AUrl;
  document.location.replace(LUrl);
end;

方案二:捕获异常并重试

若无法彻底清理残留,可在应用初始化阶段捕获异常并触发重载:

  1. 初始化时捕获重名异常
    修改主窗体 OnCreate 事件,添加异常捕获逻辑:
procedure Tfrm_Ops_Main.FormCreate(Sender: TObject);
begin
  try
    // 原有初始化逻辑
    InitAppComponents;
  except
    on E: Exception do
    begin
      if Pos('Duplicate component name', E.Message) > 0 then
      begin
        TConsole.Log('检测到组件重名,正在重载...');
        THtml.Reload_Page;
      end
      else
        raise;
    end;
  end;
end;
  1. 限制重试次数避免死循环
    通过 URL 参数记录重试次数,超过阈值则提示用户:
class procedure THtml.Reload_Page;
var
  retryCount: Integer;
  newUrl: string;
begin
  retryCount := StrToIntDef(TWebHttpRequest.QueryFields.Values['retry'], 0);
  if retryCount >= 3 then
  begin
    TWebMessageBox.Show('应用加载失败,请手动刷新页面或联系管理员');
    Exit;
  end;
  newUrl := window.location.origin + window.location.pathname + '?retry=' + IntToStr(retryCount + 1);
  document.location.replace(newUrl);
end;

内容的提问来源于stack exchange,提问作者Rohit Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 06:14:53