无法使用一个可读流写入 Node JS 中的两个不同目标

Posted

技术标签:

【中文标题】无法使用一个可读流写入 Node JS 中的两个不同目标【英文标题】:Unable to use one readable stream to write to two different targets in Node JS 【发布时间】:2020-10-31 03:37:06 【问题描述】:

我有一个客户端应用程序,用户可以在其中上传图像。我在我的 Node JS 应用程序中收到此图像作为可读数据,然后在保存之前对其进行操作:

uploadPhoto: async (server, request) =>   

        try          

            const randomString = `$uuidv4().jpg`;
            
            const stream = Fse.createWriteStream(`$rootUploadPath/$userId/$randomString`);

            const resizer = Sharp()
                                .resize(
                                    width: 450
                                );

            await data.file
                    .pipe(resizer)
                    .pipe(stream);

这工作正常,并将文件写入项目本地目录。当我尝试在同一个异步函数中再次使用相同的可读数据时,问题就出现了。请注意,所有这些代码都在 try 块中。

        const stream2 = Fse.createWriteStream(`$rootUploadPath/$userId/thumb_$randomString`);

        const resizer2 = Sharp()
                            .resize(
                                width: 45
                            );

        await data.file
                .pipe(resizer2)
                .pipe(stream2);

第二个文件已写入,但当我检查该文件时,它似乎已损坏或未成功写入数据。第一张图片总是好的。

我尝试了一些方法,发现了一种似乎有效的方法,但我不明白为什么。我在创建第二个写入流之前添加了这段代码:

    data.file.on('end', () => 
        console.log('There will be no more data.');
    );

将第二个写入流的代码放在 on-end 回调块中并没有什么区别,但是,如果我将代码留在块之外,则在第一个写入流代码和第二个写入流代码之间,然后它就可以工作了,并且两个文件都已成功写入。

让代码保持原样感觉不太对劲。有没有更好的方法可以写第二个缩略图?我尝试在第一个写入流写入数据后使用 Sharp 模块读取文件,然后创建它的较小版本,但它不起作用。该文件似乎从未准备好使用。

【问题讨论】:

当您将可读流通过管道()到第一个可写流时,它会被消耗一次。它不能被消耗两次。此外 .pipe() 不返回承诺,使用 await 没有用。请参阅 ***.com/a/58777486/510671 了解如何在 Node.js 中将 async/await 与流一起使用。 【参考方案1】:

您有 2 种选择,这取决于您的软件是如何设计的。

如果可能,我会避免在同一个“上下文”中对同一个流执行两个转换操作,例如:一个 API 端点。我宁愿将这两个不同的转换分开,这样它们就不能在同一个输入流上工作。

如果这不可能或需要进行太多更改,则解决方案是将输入流分叉并将其通过管道传输到两个不同的 Writable 中。我通常使用Highland.js fork 来完成这些任务。

另请参阅我的 cmets,了解如何使用 async/await 正确处理流,以检查写入操作何时完成。

【讨论】:

谢谢。我考虑了第一个选项,但它需要对我的 api 进行许多更改。我接受了你的第二个建议,效果很好。

以上是关于无法使用一个可读流写入 Node JS 中的两个不同目标的主要内容,如果未能解决你的问题,请参考以下文章

JS 语音合成到 Node.JS 可读流

如何在node.js中将数组值作为可读流发出/管道?

从 JavaScript 对象创建 Node.js 可读流——最简单的方法

深入node.js 3 模板引擎原理 事件 文件操作 可读流的实现原理

创建与 FormData 一起使用的可读流

Node.js——Stream