diff --git a/core/webview2.py b/core/webview2.py index 5742cc2..9d970cc 100644 --- a/core/webview2.py +++ b/core/webview2.py @@ -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-forget(ChatBridge.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: