WebView2 ExecuteScript极罕见无返回问题咨询
WebView2 ExecuteScript回调未触发与超时实现问题
核心结论
WebView2的ExecuteScript本身没有内置超时配置,这是当前API的设计限制。但你遇到的回调完全不触发问题,大概率是有前置条件没满足,先排查根源再考虑超时逻辑:
回调不触发的排查方向
- 控件未初始化完成:必须确保
FWebBrowser的CoreWebView2已经初始化完成(即CoreWebView2Ready事件已触发)。未初始化时调用ExecuteScript,回调不会被调度执行。 - JS执行异常:如果页面还未加载完成(document对象不存在),或者JS语句本身抛出未捕获异常,
ExecuteScript的回调也不会触发。可以先替换成简单测试语句(比如'return "test"')验证回调是否正常。 - UI线程被阻塞:你当前用死循环等待
TmpExecuted的写法会卡死UI线程,而WebView2的回调是在UI线程触发的——线程被占死,回调根本没机会执行。这种写法必须换掉。
自定义超时实现方案
既然API本身不支持超时,就得自己用事件+定时器的组合实现,同时避免阻塞UI线程:
var LCompletionEvent: TEvent; LTimeoutTimer: TTimer; LScriptResult: string; LIsSuccess: Boolean; begin LIsSuccess := False; // 创建手动重置事件 LCompletionEvent := TEvent.Create(nil, True, False, ''); LTimeoutTimer := TTimer.Create(nil); try // 设置5秒超时 LTimeoutTimer.Interval := 5000; LTimeoutTimer.OnTimer := procedure(Sender: TObject) begin LTimeoutTimer.Enabled := False; LCompletionEvent.SetEvent; LIsSuccess := False; // 标记超时 end; LTimeoutTimer.Enabled := True; // 执行JS脚本 FWebBrowser.ExecuteScript('document.documentElement.outerHTML', procedure(const AStrResult: string) begin LTimeoutTimer.Enabled := False; LScriptResult := AStrResult; LIsSuccess := True; LCompletionEvent.SetEvent; end); // 等待事件触发,避免死循环阻塞UI case WaitForSingleObject(LCompletionEvent.Handle, INFINITE) of WAIT_OBJECT_0: if LIsSuccess then // 处理成功结果 TmpGetDocumentAsStr := LScriptResult else // 处理超时逻辑 ShowMessage('脚本执行超时'); end; finally LTimeoutTimer.Free; LCompletionEvent.Free; end; end;
注意事项
- 绝对不要用while死循环等待,必须用事件等待+超时的方式,给UI线程留出处理回调的时间。
- 如果是在非UI线程调用
ExecuteScript,需要先切换到UI线程执行,否则回调同样可能无法触发。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

