代码示例应该比单词更能解释:
const spawn = require('child_process').spawn;
const start = new Date();
(async()=>{
const proc = spawn('( echo a; >&2 echo b; sleep 1; echo c; >&2 echo d )', { shell:true });
proc.stdout.setEncoding('utf8');
proc.stderr.setEncoding('utf8');
for await (const data of proc.stdout) {
console.log(new Date() - start, "proc stdout:", data);
}
for await (const data of proc.stderr) {
console.log(new Date() - start, "proc stderr:", data);
}
})();
这里的输出看到stderr最后出现,这在许多用例中都可以,但是我很好奇如何从两个流中获取不延迟的输出。例如,观察到的行为是:
5 'proc stdout:' 'a\n'
1006 'proc stdout:' 'c\n'
1009 'proc stderr:' 'b\nd\n'
这是有道理的,因为直到完全消耗了stdout,异步流执行才会到达第二个for循环。
我在想Promise.all或race可以被用来构建一种实现我想要的东西的方法,但是它并没有在我面前实现。另外,for await循环是唯一干净访问异步可迭代对象的唯一方法吗?
答案 0 :(得分:2)
将每个for await
放入异步IIFE中,这样您就可以从中获得一个Promise。然后,您可以呼叫Promise.all
或Promise.race
:
proc.stdout.setEncoding('utf8');
proc.stderr.setEncoding('utf8');
const stdoutProm = (async () => {
for await (const data of proc.stdout) {
console.log(new Date() - start, "proc stdout:", data);
}
})();
const stderrProm = (async () => {
for await (const data of proc.stderr) {
console.log(new Date() - start, "proc stderr:", data);
}
})();
await Promise.race([stdoutProm, stderrProm]);
// One of the iterators has been completely consumed
答案 1 :(得分:0)
您还可以将两个迭代器组合为一个:
async function* combine(a, b) {
a = a[Symbol.iterator](); b = b[Symbol.iterator]();
let doneA = false, doneB = false;
let itA = a.next().then(a => ({ a })),
itB = b.next().then(b => ({ b }));
while(true) {
const result = await Promise.race([itA, itB]);
doneA = doneA || result.a && result.a.done;
doneB = doneB || result.b && result.b.done;
if(doneA && doneB) return;
yield [result.a && result.a.value, result.b && result.b.value];
if(result.a) itA = a.next().then(a => ({ a }))
else itB = b.next().then(b => ({ b }));
}
}
可用作:
for await(const [out, err] of combine(std.out, std.err)) {
if(out) console.log(out);
if(err) console.log(err);
}