perf(webview2): avoid queuing fire-and-forget scripts

This commit is contained in:
2026-09-19 23:45:16 +08:00
parent 3b75dfcda4
commit 437e4a3213
+42 -7
View File
@@ -214,7 +214,7 @@ class Wv2Session:
self._js_pump = QTimer()
self._js_pump.setInterval(25)
self._js_pump.timeout.connect(self._js_pump_tick)
self._js_pump.start()
# 无回调脚本不进入队列;没有待处理任务时不需要常驻唤醒 UI 线程。
# 🆕 预热:立即导航 about:blank,让 msedgewebview2 进程/GPU 在 UI 构建期间冷启动
# (实测本机首次真实页面导航需 12-15s,预热后降到 ~1s)
try:
@@ -339,8 +339,27 @@ class Wv2Session:
print("[WV2] navigate error:", ex)
def execute_js(self, script: str):
"""fire-and-forgetChatBridge.run_js 的替换,JS 文本完全同构)"""
self._js_run(script, None)
"""执行无需返回值的脚本,不进入结果轮询队列。
流式正文每个 token 都会走这里。旧实现统一使用
``ExecuteScriptWithResultAsync`` 并把任务放入 ``_js_pending``,高频
输出时会在渲染器和 Python 侧同时堆积大量无用结果;WebView2 原生
``ExecuteScriptAsync`` 已经提供了真正的 fire-and-forget 路径。
"""
try:
execute_async = getattr(self.core, "ExecuteScriptAsync")
except AttributeError:
# 兼容旧版/测试替身未暴露 ExecuteScriptAsync 的情况。即使只能
# 使用带结果 API,也直接丢弃 Task,不把无用结果放进轮询队列。
try:
getattr(self.core, "ExecuteScriptWithResultAsync")(script)
except BaseException as ex:
print("[WV2] execute_js fallback error:", ex)
return
try:
execute_async(script)
except BaseException as ex:
print("[WV2] execute_js error:", ex)
def execute_js_async(self, script: str, cb):
"""带回调执行:真异步,回调在主线程定时器 tick 中发出(绝不阻塞)"""
@@ -358,13 +377,25 @@ class Wv2Session:
pass
return
self._js_pending.append([task, cb, time.time()])
try:
if not self._js_pump.isActive():
self._js_pump.start()
except Exception:
pass
def _js_pump_tick(self):
if not self._js_pending:
try:
self._js_pump.stop()
except Exception:
pass
return
import json
remaining = []
for task, cb, t0 in self._js_pending:
# 先摘下本批次;回调中再次入队的任务写入新的 _js_pending,不能被
# 本轮收尾赋值覆盖。
pending = self._js_pending
self._js_pending = []
for task, cb, t0 in pending:
done = False
try:
done = task.IsCompleted
@@ -373,7 +404,7 @@ class Wv2Session:
if not done and time.time() - t0 > 10:
done = True # 10s 安全超时(渲染器死亡时不永久卡队列)
if not done:
remaining.append([task, cb, t0])
self._js_pending.append([task, cb, t0])
continue
result = None
try:
@@ -395,7 +426,11 @@ class Wv2Session:
cb(result)
except Exception as ex:
print("[WV2] js callback error:", ex)
self._js_pending = remaining
if not self._js_pending:
try:
self._js_pump.stop()
except Exception:
pass
def close(self):
try: