Deno如何在子进程结束前执行Shell命令并读取输出?
在Deno中实时读取子进程输出以抓取Chrome DevTools调试地址
在Deno中可以通过异步读取子进程的标准输出流实现进程未结束前获取输出,无需等待进程退出。针对你的Chrome启动场景,具体实现步骤如下:
核心思路
使用Deno.Command(Deno 1.20+支持,你的1.36.3版本完全兼容)启动子进程,将标准输出配置为可管道读取模式,然后异步监听输出流,逐行匹配并提取DevTools的WebSocket地址。
完整代码示例
// 构建Chrome启动命令 const chromeCmd = new Deno.Command( "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", { args: [ "--remote-debugging-port=9222", "--no-first-run", "--no-default-browser-check", `--user-data-dir=${Deno.makeTempDirSync({ prefix: "chrome-remote_data_dir" })}`, ], stdout: "piped", // 开启标准输出管道 stderr: "piped", // 可选:同时捕获错误输出 }, ); // 启动子进程 const childProcess = chromeCmd.spawn(); // 异步读取标准输出流 async function captureDevToolsUrl() { const reader = childProcess.stdout.readable.getReader(); const decoder = new TextDecoder(); let buffer = ""; try { while (true) { const { done, value } = await reader.read(); if (done) break; // 将二进制数据解码为文本并追加到缓冲区 buffer += decoder.decode(value, { stream: true }); // 按行分割处理输出 const lines = buffer.split("\n"); buffer = lines.pop() || ""; // 保留未完成的行 for (const line of lines) { // 匹配DevTools的WebSocket地址 const match = line.match(/DevTools listening on (ws:\/\/127\.0\.0\.1:9222\/devtools\/browser\/[\w-]+)/); if (match) { const devToolsUrl = match[1]; console.log("捕获到DevTools调试地址:", devToolsUrl); // 这里可以添加你的业务逻辑,比如保存地址、调用其他接口等 // 无需关闭进程,Chrome会继续运行 return devToolsUrl; } } } } catch (err) { console.error("读取输出时出错:", err); } finally { reader.releaseLock(); } } // 启动捕获任务 captureDevToolsUrl(); // 可选:监听子进程退出事件 childProcess.status.then((status) => { console.log("Chrome进程已退出,退出码:", status.code); });
关键说明
stdout: "piped":这是实现实时读取的核心配置,让子进程的标准输出通过管道传递给Deno进程,而非等待进程结束后一次性返回。- 流读取器
getReader():通过异步迭代的方式逐块读取输出,避免阻塞主线程。 - 缓冲区处理:因为输出可能以二进制块形式返回,需要拼接成完整的行后再进行正则匹配,避免截断内容。
- 进程持续运行:使用
spawn()启动进程而非output(),后者会等待进程结束才返回结果,而spawn()会立即返回子进程实例,让Chrome保持运行状态。
额外提示
如果需要同时处理错误输出,可以参照标准输出的方式读取childProcess.stderr流。另外,临时目录的创建也可以用Deno.makeTempDirSync替代shell的mktemp,更符合Deno的原生API习惯。
内容的提问来源于stack exchange,提问作者user1763684
相关产品推荐
相关产品推荐

