阅读 91

Deno中与子进程相互通讯的实现

本来打算放到自己的博客网站上的,因为还处于施工阶段就先放在这里吧,主要是怕以后又忘记怎么解决这个问题了。

前言

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写的,提示信息还真完全!我发现stdoutReader类型,让我想想,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')事件处理。

我将这个解决方法记录于此,希望对遇到同样问题的同学有所帮助.

文章分类
后端
文章标签