Node.js Streams vs. Observables

时间:2015-05-24 12:18:34

标签: javascript node.js reactive-programming rxjs bacon.js

在了解Observables后,我发现它们与Node.js streams非常相似。两者都有一种机制,可以在新数据到达时发出消息,发生错误或没有更多数据(EOF)。

我很想了解两者之间的概念/功能差异。谢谢!

1 个答案:

答案 0 :(得分:87)

Observables 和node.js的 Streams 都允许您解决相同的基本问题:异步处理一系列值。我相信,两者之间的主要区别在于它的外观背景。该术语反映在术语和API中。

Observables 一侧,您有一个EcmaScript扩展,它引入了反应式编程模型。它试图用ObserverObservable的极简主义和可组合的概念填补价值生成和异步性之间的空白。

在node.js和 Streams 方面,您希望为网络流和本地文件的异步和高性能处理创建一个接口。该术语源自该初始上下文,您可以获得pipechunkencodingflushDuplexBuffer等。一种实用的方法,为特定的用例提供明确的支持,你失去了一些组合事物的能力,因为它不是那么统一。例如,您在push流上使用Readable,在write上使用Writable,但从概念上讲,您正在做同样的事情:发布值。

因此,在实践中,如果您查看概念,并且使用选项{ objectMode: true },则可以将ObservableReadable流和Observer匹配Writable流。var Readable = require('stream').Readable; var Writable = require('stream').Writable; var util = require('util'); var Observable = function(subscriber) { this.subscribe = subscriber; } var Subscription = function(unsubscribe) { this.unsubscribe = unsubscribe; } Observable.fromReadable = function(readable) { return new Observable(function(observer) { function nop() {}; var nextFn = observer.next ? observer.next.bind(observer) : nop; var returnFn = observer.return ? observer.return.bind(observer) : nop; var throwFn = observer.throw ? observer.throw.bind(observer) : nop; readable.on('data', nextFn); readable.on('end', returnFn); readable.on('error', throwFn); return new Subscription(function() { readable.removeListener('data', nextFn); readable.removeListener('end', returnFn); readable.removeListener('error', throwFn); }); }); } var Observer = function(handlers) { function nop() {}; this.next = handlers.next || nop; this.return = handlers.return || nop; this.throw = handlers.throw || nop; } Observer.fromWritable = function(writable, shouldEnd, throwFn) { return new Observer({ next: writable.write.bind(writable), return: shouldEnd ? writable.end.bind(writable) : function() {}, throw: throwFn }); } 。您甚至可以在两个模型之间创建一些简单的适配器。

Observer

您可能已经注意到我更改了一些名称,并使用了此处介绍的SubscriptionGenerator更简单的概念,以避免 Observables 完成的重复性过载在Subscription。基本上,Observable允许您取消订阅pipe。无论如何,使用上面的代码,您可以拥有Observable.fromReadable(process.stdin).subscribe(Observer.fromWritable(process.stdout));

process.stdin.pipe(process.stdout)

Readable相比,您所拥有的是一种组合,过滤和转换流的方法,这些流也适用于任何其他数据序列。您可以使用TransformWritableReadable流来实现它,但API支持子类化而不是链接Observable和应用函数。在Transform模型上,例如,转换值对应于将变换器函数应用于流。它不需要Observable.just = function(/*... arguments*/) { var values = arguments; return new Observable(function(observer) { [].forEach.call(values, function(value) { observer.next(value); }); observer.return(); return new Subscription(function() {}); }); }; Observable.prototype.transform = function(transformer) { var source = this; return new Observable(function(observer) { return source.subscribe({ next: function(v) { observer.next(transformer(v)); }, return: observer.return.bind(observer), throw: observer.throw.bind(observer) }); }); }; Observable.just(1, 2, 3, 4, 5).transform(JSON.stringify) .subscribe(Observer.fromWritable(process.stdout)) 的新子类型。

Observable

结论?在任何地方引入反应模型和sqlText= "Select *" sqlText = sqlText & " From MyStudent" sqlText = sqlText & " Where Name LIKE CONCAT('%', ? ,'%')" Set dbRec = new ADODB.RecordSet Set dbCmd = new ADODB.Command With dbCmd .ActiveConnection = dbCon .CommandType = adCmdText .CommandText = SqlText End with dbCmd.Parameters.Append dbCmd.CreateParameter("PNMKM", adVarChar, adParamInput, 20) dbCmd.Parameters("PNMKM").Value = Trim$(inpNMKM.Text) 概念都很容易。围绕这个概念实现整个库变得更加困难。所有这些小功能需要始终如一地协同工作。毕竟,ReactiveX项目仍在进行中。但是,如果你真的需要将文件内容发送到客户端,处理编码,然后在NodeJS中将其压缩,那么它的效果非常好。