翻译:猖獗的手艺宅
本文首发微信民众号:jingchengyideng
迎接关注,天天都给你推送新颖的前端手艺文章
在本中,我们在 Node.js 中把 shell 敕令作为子历程运转。然后异步读取这些历程的 stdout 并写入其 stdin。
在子历程中运转 shell 敕令
首先从在子历程中运转 shell 敕令最先:
const {onExit} = require('@rauschma/stringio');
const {spawn} = require('child_process');
async function main() {
const filePath = process.argv[2];
console.log('INPUT: '+filePath);
const childProcess = spawn('cat', [filePath],
{stdio: [process.stdin, process.stdout, process.stderr]}); // (A)
await onExit(childProcess); // (B)
console.log('### DONE');
}
main();
诠释:
我们用了
spawn()
,它可以使我们在敕令运转时接见敕令的 stdin,stdout 和 stderr。- 在 A 行中,我们将子历程的 stdin 衔接到当前历程的 stdin。
- B 行守候该历程完成。
守候子历程经由过程 Promise 退出
函数 onExit()
以下所示。
function onExit(childProcess: ChildProcess): Promise<void> {
return new Promise((resolve, reject) => {
childProcess.once('exit', (code: number, signal: string) => {
if (code === 0) {
resolve(undefined);
} else {
reject(new Error('Exit with error code: '+code));
}
});
childProcess.once('error', (err: Error) => {
reject(err);
});
});
}
子历程的完成
以下代码用 @rauschma/stringio
异步写入以 shell 敕令运转的子历程的 stdin
:
const {streamWrite, streamEnd, onExit} = require('@rauschma/stringio');
const {spawn} = require('child_process');
async function main() {
const sink = spawn('cat', [],
{stdio: ['pipe', process.stdout, process.stderr]}); // (A)
writeToWritable(sink.stdin); // (B)
await onExit(sink);
console.log('### DONE');
}
main();
async function writeToWritable(writable) {
await streamWrite(writable, 'First line\n');
await streamWrite(writable, 'Second line\n');
await streamEnd(writable);
}
我们为 shell 敕令天生一个名为 sink
的自力历程。用 writeToWritable
写入 sink.stdin
。它借助 await
异步实行并停息,以防止缓冲区被斲丧太多。
诠释:
- 在A行中,我们通知
spawn()
经由过程sink.stdin
('pipe'
)接见 stdin。 stdout 和 stderr 被转发到process.stdin
和process.stderr
,如前面所述。 - 在B行中不会
await
写完成。而是await
子历程sink
完成。
接下来相识 streamWrite()
的事情道理。
写流操纵的 promise
Node.js 写流的操纵一般触及回调(拜见文档)。代码以下。
function streamWrite(
stream: Writable,
chunk: string|Buffer|Uint8Array,
encoding='utf8'): Promise<void> {
return new Promise((resolve, reject) => {
const errListener = (err: Error) => {
stream.removeListener('error', errListener);
reject(err);
};
stream.addListener('error', errListener);
const callback = () => {
stream.removeListener('error', errListener);
resolve(undefined);
};
stream.write(chunk, encoding, callback);
});
}
streamEnd()
的事情方式是相似的。
从子历程中读取数据
下面的代码运用异步迭代(C行)来读取子历程的 stdout
中的内容:
const {chunksToLinesAsync, chomp} = require('@rauschma/stringio');
const {spawn} = require('child_process');
async function main() {
const filePath = process.argv[2];
console.log('INPUT: '+filePath);
const source = spawn('cat', [filePath],
{stdio: ['ignore', 'pipe', process.stderr]}); // (A)
await echoReadable(source.stdout); // (B)
console.log('### DONE');
}
main();
async function echoReadable(readable) {
for await (const line of chunksToLinesAsync(readable)) { // (C)
console.log('LINE: '+chomp(line))
}
}
诠释:
- A行:我们疏忽 stdin,愿望经由过程流接见 stdout 并将 stderr 转发到
process.stderr
。 - B行:最先
awat
直到echoReadable()
完成。没有这个await
,DONE
将会在挪用source.stdout
之前被输出。
在子历程之间举行管道衔接
鄙人面的例子中,函数transform()
将会:
从
source
子历程的stdout
中读取内容。- 将内容写入
sink
子历程的stdin
。
- 将内容写入
换句话说,我们正在完成相似 Unix 管道的功用:
cat someFile.txt | transform() | cat
这是代码:
const {chunksToLinesAsync, streamWrite, streamEnd, onExit}
= require('@rauschma/stringio');
const {spawn} = require('child_process');
async function main() {
const filePath = process.argv[2];
console.log('INPUT: '+filePath);
const source = spawn('cat', [filePath],
{stdio: ['ignore', 'pipe', process.stderr]});
const sink = spawn('cat', [],
{stdio: ['pipe', process.stdout, process.stderr]});
transform(source.stdout, sink.stdin);
await onExit(sink);
console.log('### DONE');
}
main();
async function transform(readable, writable) {
for await (const line of chunksToLinesAsync(readable)) {
await streamWrite(writable, '@ '+line);
}
await streamEnd(writable);
}
扩大浏览
- 博客:“经由过程 Node.js 的异步迭代读取流”
- “探究ES2018和ES2019”中的“异步迭代 一章
- “探究ES2016和ES2017”中的“异步功用” 一章
迎接继承浏览本专栏别的高赞文章:
- 12个令人惊叹的CSS试验项目
- 天下顶级公司的前端口试都问些什么
- CSS Flexbox 可视化手册
- 过节很无聊?照样用 JavaScript 写一个脑力小游戏吧!
- 从设计者的角度看 React
- CSS粘性定位是如何事情的
- 一步步教你用HTML5 SVG完成动画结果
- 程序员30岁前月薪达不到30K,该何去何从
- 第三方CSS平安吗?
- 谈谈super(props) 的重要性