本来打算放到自己的博客网站上的,因为还处于施工阶段就先放在这里吧,主要是怕以后又忘记怎么解决这个问题了。
前言
Deno大家应该都知道的吧,就是那个Node.js重新排列了字母组合后的新的后端运行时。以前用惯了Node.js,写写子进程交互什么的非常轻松,今天突发奇想想在Deno也实现一下,好为以后的项目做准备,于是就开始动手实验了。
车到山前疑无路
万万没想到啊,Deno对子进程的调用只剩下一个内建方法Deno.run,感觉有点简陋啊,不知道能不能实现相互通信。先看看文档吧,怎么比Node.js少了那么多的选项,心里莫名的感觉不妙。
先按照文档中的例子走一遍吧
/**
* subprocess.ts
*/
const fileNames = Deno.args;
const p = Deno.run({
cmd: [
"deno",
"run",
"--allow-read",
"https://deno.land/std@0.93.0/examples/cat.ts",
...fileNames,
],
stdout: "piped",
stderr: "piped",
});
const { code } = await p.status();
// Reading the outputs closes their pipes
const rawOutput = await p.output();
const rawError = await p.stderrOutput();
if (code === 0) {
await Deno.stdout.write(rawOutput);
} else {
const errorString = new TextDecoder().decode(rawError);
console.log(errorString);
}
Deno.exit(code);
这里使用的是文档中与子进程交互的演示代码,运行的时候要加上--allow-run参数才能正常运行。
这个演示代码只能当子程序运行完成之后才能显示输出结果,这个不是我想要的效果,我的子程序会在运行过程中输出结果,并且能够接收父进程的输入,你都运行完了才显示出来还有什么用。
于是我开起了搜索之旅,然而令我非常失望的是现在Deno的资料太少了,搜索了半天都是跟文档中一样的方法来处理输出消息。
柳暗花明又一村
我在编辑器中不断尝试,看看能不能找到一些有用的线索,果然我发现了stdout这个属性,但是坑爹的是这个属性居然没有出现在文档中!这是要自己理解吗?幸亏Deno使用Typescript写的,提示信息还真完全!我发现stdout是Reader类型,让我想想,Deno和Node.js的作者是同一个人,Streamer这个设计在Node.js中是与event齐名的优秀设计,那么Deno中应该会保留Streamer操作才对,Streamer是数据流读取,那么就有可能在子进程运行的时候获取到输出消息了。
又经过了一番搜索发现Deno把Streamer操作独立出去了,不属于运行时API部分,需要到Deno.std库中找,又是一番搜寻终于让我找到了需要的解决方法,记录于下
import { readStringDelim } from "https://deno.land/std@0.93.0/io/mod.ts";
const p = Deno.run({
cmd: ['./qplayer', '--uri=file:///../test.mp3', '--output=local', '--silent'],
stderr: 'piped',
stdout: 'piped',
});
for await (let line of readStringDelim(p.stderr, "\n")) {
console.log(line)
}
p.close();
这里最关键的是readStringDelim方法,这个方法会返回一个遍历对象,有了这个对象就可以使用for await()来进行异步处理,相当于Node.js中on('data')事件处理。
我将这个解决方法记录于此,希望对遇到同样问题的同学有所帮助.