簡體   English   中英

Node.js Streams vs. Observables

[英]Node.js Streams vs. Observables

在了解了Observables之后 ,我發現它們與Node.js流非常相似。 兩者都有一種機制,可以在新數據到達時通知消費者,發生錯誤或沒有更多數據(EOF)。

我很想了解兩者之間的概念/功能差異。 謝謝!

Observables和node.js的Streams都允許您解決相同的底層問題:異步處理一系列值。 我相信,兩者之間的主要區別在於它的外觀背景。 該上下文反映在術語和API中。

Observables方面,您有一個EcmaScript的擴展,它引入了反應式編程模型。 它試圖用ObserverObservable的極簡主義和可組合的概念填補價值生成和異步性之間的空白。

在node.js和Streams端,您希望為網絡流和本地文件的異步和高性能處理創建一個接口。 術語源自初始上下文,您可以獲得pipechunkencodingflushDuplexBuffer等。通過采用實用的方法為特定用例提供顯式支持,您將失去一些組合事物的能力,因為它不是那么統一。 例如,您可以使用pushReadable數據流和writeWritable ,雖然,在概念上,你正在做同樣的事情:發布的值。

因此,在實踐中,如果查看概念,並且使用選項{ objectMode: true } ,則可以將ObservableReadable流和ObserverWritable流匹配。 您甚至可以在兩個模型之間創建一些簡單的適配器。

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
    });
}

您可能已經注意到我更改了一些名稱並使用了此處介紹的更簡單的ObserverSubscription概念,以避免由GeneratorObservables完成的重復性過載。 基本上, Subscription允許您取消訂閱Observable 無論如何,使用上面的代碼你可以有一個pipe

Observable.fromReadable(process.stdin).subscribe(Observer.fromWritable(process.stdout));

process.stdin.pipe(process.stdout)相比,您所擁有的是一種組合,過濾和轉換流的方法,這些流也適用於任何其他數據序列。 您可以使用ReadableTransformWritable流實現它,但API支持子類化而不是鏈接Readable和應用函數。 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概念。 圍繞這個概念實現整個庫更加困難。 所有這些小功能需要始終如一地協同工作。 畢竟, ReactiveX項目仍在繼續。 但是如果你真的需要將文件內容發送到客戶端,處理編碼,然后在NodeJS中將其壓縮,那么它的效果非常好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM