请原谅我这个愚蠢的问题,但我有点困惑在 NodeJS 中流式传输有什么大惊小怪。
我知道流式处理允许我们一次发送数据块,从而改善最终用户的体验
但是,这不已经是互联网上数据传输的标准方式吗?在哪里,在客户端和服务器之间建立套接字连接,并通过数据包发送数据?
套接字 == 流 && 和数据包 == 块,对吧?
这根本不是重点。
您是对的,通过TCP/IP通信在点对点HTTP中传递的一系列数据包。
但是,请考虑允许您查看部分文件的网站,以及强制您在开始播放之前等待整个文件准备就绪的站点。
区别在于客户端和服务器同意的是"完整"文档。
在最后一个示例中,该文件是完整的文档。服务器无法(/不愿意(提供比完整文件更精细的文档;因此,您的浏览器必须等到整个文件下载完成,然后才能舒适地使用它。
在另一个宇宙中,一个完整的"文档"可能是一组字节,这些字节与标头信息一起传递回去,指定这些字节在总文件中的位置,允许搜索文档,在有部分内容时播放,等等。当播放器的缓冲内容用完时,它将寻找下一部分,该部分恰好是由另一组字节组成的资源,从其当前内容之后的字节开始。
不过,这与Node关系不大,而与HTTP1.1关系更大
。其他形式的套接字连接(WebSockets,UDP等(具有不同的行为和期望。
仍然与Node关系不大,尽管Node的流确实可以轻松支持服务器之间的流通信,以及一种或另一种形式的客户端之间的流通信,无论是否通过HTTP。
好的,所以有了这个覆盖并离开了......那么,节点"流"是什么,如果不是专门针对分块通信的呢?
要掌握这一点,最简单的方法是从基于 set(/collection( 的编程概念开始。
曾几何时,如果我有一个想要加倍的数字列表,我可能会写如下内容:
var numbers = [1, 2, 3];
var number;
var doubles = [];
var i = 0,
l = numbers.length;
for (; i < l; i += 1) {
number = numbers[i];
doubles.push( number * 2 );
}
不过,这些天我会使用 .map
来删除所有的循环管理,而是专注于我想应用于每个元素的微小原子操作:
const numbers = [1, 2, 3];
const doubles = numbers.map(x => x * 2);
右?这大大降低了复杂性。当然,如果我想继续将额外的变换链接到后面,我可以。
numbers
.map(double)
.map(add1)
.filter(gt5)
.map( ... ) // etc
所以现在你看到更多的函数式、基于集合的编程就是一次声明一个操作,一次声明一个元素.........溪流从何而来?
井。。。。。。如果您正在映射和过滤(和减少(的数组没有完成怎么办?如果它在这个系统运行时被其他进程异步填充怎么办?
它可能是通过分块的HTTP1.1流量填充的,当然......但这远非必要条件。相反,它可以由超时、系统操作、数据库或阳光下的任何其他内容填充。
如果我有一个神奇的服务,给了我一条流,我可能会这样使用它:
// returns a stream which fires on *every* returned row
db.streamQuery( "select * from ........" )
// turned into domain objects in your system
.pipe( transformRecordIntoObject )
// remove private data (DB keys, admin properties, whatever)
.pipe( removeInternalObjectProperties )
// remove entries which aren't wanted/helpful, for one reason or another
.pipe( filterOutUnwantedEntries )
// buffer entries up, to serve an array of 100 at a time
.pipe( bufferEvery100AsJSON )
// send the JSON of 100 results (at a time) straight to the client who requested them
.pipe( res );
如您所见,流本身(提供接受连接流的.pipe
(与 HTTP 通信关系不大......
...也就是说,它们非常适合,并且您在HTTP请求中拥有的req
和res
对象确实分别是可读和可写的流,因此,您可以以这种方式从它们/到它们进行管道传输。
故意跳过了特定的实现细节,以及尾端的特定通信要求,我正在通过网络发送一些 JSON.........对于典型的HTTP响应(包括基于范围的内容流(,这将需要更多的工作,但是对于ServerSent Events,没有比这更多的工作了。
我希望这有助于解释您可能期望的内容和您一直在阅读的内容之间的一些差异......以及流套接字通信与功能流之间的一些交叉,这些流可能在 Node 和 Scala 中找到,Bash| 中的终端命令管道Powershell|等,以及其他一些地方。