跳到內容

解決 Browser Evaluate 造成的頁面卡死:引入 CDP 重構方案

寫自動化指令碼最怕遇到一種情況:你明明只是想在頁面跑一段簡單的 JavaScript,結果因為那段 code 執行太久或意外卡住,導致後續所有的 click 或 type 動作全部跟著排隊卡死。

這通常是因為底層工具將所有指令序列化處理,一旦前面的 evaluate 沒結束,後面的指令就進不去。這種「一人卡關,全家報銷」的開發痛點,正是我們這次重構要解決的核心問題。

在開始之前,請確保你的環境符合以下條件(依據源文件):

  • 已開啟 browser.evaluateEnabled 功能閘門
  • 擁有可存取的 CDP (Chrome DevTools Protocol) endpoint
  • 現有的 Playwright 基礎設施

我們將棄用單一的 Playwright 指令隊列,改用 CDP 建立獨立的執行通道。

首先,我們需要一個統一的預算機制,確保 timeoutMs 和 AbortSignal 在整個鏈路中行為一致。

// 範例:建立統一預算助手
const budget = createBudget({ timeoutMs, signal });
// 獲得一致的 signal, deadlineAtMs, 以及 remainingMs()

建立一個不走 Playwright 隊列的執行路徑。這會開啟一個獨立的 WebSocket 連接。

// src/browser/cdp-evaluate.ts 核心邏輯
// 1. 連接到 browser-level CDP socket
// 2. 使用 Target.attachToTarget 獲取 sessionId
// 3. 執行 Runtime.evaluate 或 Runtime.callFunctionOn

為了讓 CDP 能精準選取元素,我們在 Snapshot 階段就把 backendDOMNodeId 存起來。

// 擴展後的 Ref 結構
{
role: string;
name: string;
nth: number;
backendDOMNodeId?: number; // 新增:用於 CDP 定位
}

更新 act:evaluate 的處理邏輯:

  • 如果沒有 ref 或 ref 包含 backendDOMNodeId:直接走 CDP 路徑,速度快且不阻塞。
  • 如果無法對應到 ID:回退到 Playwright 路徑(保留現有的安全網)。

以下是根據重構計劃預見的常見問題與對策:

問題:CDP 元素對應(Mapping)失敗怎麼辦? 解決方案:這套機制是 best-effort 的。如果無法將 (role, name, nth) 對應到 backendDOMNodeId,系統會自動回退到原本的 Playwright 執行路徑,雖然會有阻塞風險,但能確保功能不中斷。

問題:執行 JavaScript 逾時會影響頁面嗎? 解決方案:當觸發逾時或中止時,我們會發送 Runtime.terminateExecution。這雖然可能產生副作用,但能有效釋放資源。這是為了防止分頁永久卡死的必要權衡。

問題:如果環境不支援 CDP Attach 怎麼辦? 解決方案:我們會保留現有的最後手段(Last Resort)復原路徑,包括斷開 Playwright 連線來強行恢復分頁狀態。

想要針對你的專案環境進行更具體的設定嗎?歡迎諮詢 AI Setup Assistant。

  • 查看 Accessibility.getFullAXTree 相關文件
  • 了解 Runtime.terminateExecution 的執行細節
  • 閱讀 PR #13498 關於安全網的初步實作
  • 探索 BrowserActRequest 的完整 API 規範
OpenClaw

OpenClaw Expert

還是卡住了?

如果這篇文件沒有解決你的情境,直接問 OpenClaw Expert,拿到可執行步驟。