成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Rxjs 響應(yīng)式編程-第一章:響應(yīng)式

songze / 999人閱讀

摘要:響應(yīng)式編程具有很強(qiáng)的表現(xiàn)力,舉個例子來說,限制鼠標(biāo)重復(fù)點擊的例子。在響應(yīng)式編程中,我把鼠標(biāo)點擊事件作為一個我們可以查詢和操作的持續(xù)的流事件。這在響應(yīng)式編程中尤其重要,因為我們隨著時間變換會產(chǎn)生很多狀態(tài)片段。迭代器模式的另一主要部分來自模式。

Rxjs 響應(yīng)式編程-第一章:響應(yīng)式
Rxjs 響應(yīng)式編程-第二章:序列的深入研究
Rxjs 響應(yīng)式編程-第三章: 構(gòu)建并發(fā)程序
Rxjs 響應(yīng)式編程-第四章 構(gòu)建完整的Web應(yīng)用程序
Rxjs 響應(yīng)式編程-第五章 使用Schedulers管理時間
Rxjs 響應(yīng)式編程-第六章 使用Cycle.js的響應(yīng)式Web應(yīng)用程序

響應(yīng)式

現(xiàn)實世界相當(dāng)混亂:事件不按照順序發(fā)生,應(yīng)用崩潰,網(wǎng)絡(luò)不通。幾乎沒有應(yīng)用是完全同步的,所以我們不得不寫一些異步代碼保持應(yīng)用的可響應(yīng)性。大多數(shù)的時候是很痛苦的,但也并不是不可避免。

現(xiàn)代應(yīng)用需要超級快速的響應(yīng)速度,并且希望能夠不漏掉一個字節(jié)的處理來自不同數(shù)據(jù)源的數(shù)據(jù)。然而并沒有現(xiàn)成的解決方案,因為它們不會隨著我們添加并發(fā)和應(yīng)用程序狀態(tài)而擴(kuò)展代碼變得越來越復(fù)雜。

本章向您介紹反應(yīng)式編程,這是一種自然,簡單的方法處理異步代碼的方式。我會告訴你事件的流程 - 我們稱之為Observables - 是處理異步代碼的一種很好的方式。
然后我們將創(chuàng)建一個Observable,看看響應(yīng)式思維和RxJS是怎么樣改善現(xiàn)有技術(shù),讓你成為更快樂,更多高效的程序員。

什么是響應(yīng)式?

讓我們從一個小的響應(yīng)性RxJS程序開始。 這個程序需要通過單擊按鈕檢索來自不同來源的數(shù)據(jù),它具有以下要求:

它必須統(tǒng)一來自使用不同源的JSON結(jié)構(gòu)

最終結(jié)果不應(yīng)包含任何副本

為了避免多次請求數(shù)據(jù),用戶不能重復(fù)點擊按鈕

使用RxJS,我們的代碼類似這樣:

var button = document.getElementById("retrieveDataBtn");
var source1 = Rx.DOM.getJSON("/resource1").pluck("name");
var source2 = Rx.DOM.getJSON("/resource2").pluck("props", "name");
function getResults(amount) {
    return source1.merge(source2)
        .pluck("names")
        .flatMap(function(array) { return Rx.Observable.from(array); })
        .distinct()
        .take(amount);
}
var clicks = Rx.Observable.fromEvent(button, "click");
clicks.debounce(1000)
    .flatMap(getResults(5))
    .subscribe(
        function(value) { console.log("Received value", value); },
        function(err) { console.error(err); },
        function() { console.log("All values retrieved!"); }
    );

不要擔(dān)心不理解這里的代碼。只要關(guān)注于成果即可。你看到的第一件事是我們使用更少的代碼實現(xiàn)更多的功能。我們通過使用Observable來實現(xiàn)這一目標(biāo)。

Observable表示數(shù)據(jù)流。程序也可以可以主要表示為數(shù)據(jù)流。在前面的示例中,兩個遠(yuǎn)程源是Observables,用戶點擊鼠標(biāo)也是如此。實際上,我們的程序本質(zhì)上是一個由按鈕的單擊事件構(gòu)成的Observable,我們把它轉(zhuǎn)變成獲得我們想要的結(jié)果。

響應(yīng)式編程具有很強(qiáng)的表現(xiàn)力,舉個例子來說,限制鼠標(biāo)重復(fù)點擊的例子。想象一下我們使用我們使用promise和callback實現(xiàn)這個功能是有多復(fù)雜:我們需要每秒重置一下點擊次數(shù),并且在用戶點擊之后每秒都要保存點擊狀態(tài)。但是這樣子,對于這個小功能來說就顯得過于復(fù)雜了,并且所寫代碼與業(yè)務(wù)功能并沒有直觀的聯(lián)系。為了彌補(bǔ)基礎(chǔ)代碼庫的功能不足,在一個大型應(yīng)用中,這些很小的復(fù)雜功能會增加的非??臁?/p>

通過響應(yīng)式編,我們使用debounce方法來限制點擊流次數(shù)。這樣就保證每次點擊的間隔時間至少1s,忽略1s之間的點擊次數(shù)。我們不關(guān)心內(nèi)部如何實現(xiàn),我們只是表達(dá)我們希望代碼執(zhí)行的操作,而不是如何操作。

這就變得更有趣了。接下來,您將看到反應(yīng)式編程如何幫助我們提高課程效率和表現(xiàn)力。

電子表格是可響應(yīng)的

讓我們從這樣一個響應(yīng)性系統(tǒng)的典型例子開始考慮:點子表格。我們都是使用過吧,但我們很少停下來思考它們是多么令人震驚的直觀。假設(shè)我們在電子表格的單元格A1中有一個值,然后我們可以在電子表格中的其他單元格中引用它,并且每當(dāng)我們更改A1時,每個依賴于A1的單元格都會自動更新與A1同步。

這些操作對我們感覺很自然,我們并不會去告訴計算機(jī)去根據(jù)A1更新單元格或者如何更新;這些單元格就自動這樣子做了。在點子表格中,我們只需要簡單的聲明我們需要處理的問題,不用操心計算機(jī)如何處理。

鼠標(biāo)輸入作為streams

理解如何把事件作為流,我們回想一下本章開頭的那個程序。在那里,我們使用鼠標(biāo)點擊作為用戶點擊時實時生成的無限事件流。這個想法起源于Erik Meijer,也就是Rxjs的作者。他認(rèn)為:你的鼠標(biāo)就是一個數(shù)據(jù)庫。

在響應(yīng)式編程中,我把鼠標(biāo)點擊事件作為一個我們可以查詢和操作的持續(xù)的流事件。想象成流而不是一個孤立的事件,這種想法開辟了一種全新的思考方式。我們可以在其中操縱尚未創(chuàng)建的整個值的流。

好好想想。這種方式有別于我們以往的編程方式,之前我們把數(shù)據(jù)存儲在數(shù)據(jù)庫,或者數(shù)組并且等待這些數(shù)據(jù)可用之后在使用它們。如果它們尚不可用(舉個例子:一個網(wǎng)絡(luò)請求),我們只能等它們好了才可以使用。

我們可以將流視為所在由時間而不是存儲位置分開的數(shù)組。無論是時間還是存儲位,我們都有元素序列:

將您的程序視為流動的數(shù)據(jù)序列是理解的RxJS程序的關(guān)鍵。這需要一些練習(xí),但并不難。事實上,大多數(shù)我們在任何應(yīng)用程序中使用的數(shù)據(jù)都可以表示為序列。

序列查詢

讓我們使用傳統(tǒng)javascript傳統(tǒng)的事件綁定技術(shù)來實現(xiàn)一個鼠標(biāo)點擊流。要記錄鼠標(biāo)點擊的x和y坐標(biāo),我們可以這樣寫:

ch1/thinking_sequences1.js

document.body.addEventListener("mousemove", function(e) {
    console.log(e.clientX, e.clientY);
});

此代碼將按順序打印每次鼠標(biāo)單擊的x坐標(biāo)和y坐標(biāo)。

輸出如下:

252 183
211 232
153 323
...

看起來像一個序列,不是嗎? 當(dāng)然,問題在于操縱事件并不像操縱數(shù)組那么容易。 例如,如果我們想要更改前面的代碼,使其僅記錄前10次位于屏幕右側(cè)的單擊事件(相當(dāng)隨機(jī)的目標(biāo)),我們會寫像這樣的東西:

var clicks = 0;
document.addEventListener("click", function registerClicks(e) {
    if (clicks < 10) {
        if (e.clientX > window.innerWidth / 2) {
            console.log(e.clientX, e.clientY);
            clicks += 1;
        }
    } else {
        document.removeEventListener("click", registerClicks);
    }
});

為了滿足我們的要求,我們通過引入一個全局變量作為擴(kuò)展?fàn)顟B(tài)來記錄當(dāng)前點擊數(shù)。 我們還需要使用嵌套的條件來檢查兩個不同的條件。當(dāng)我們完成時,我們必須注銷事件,以免泄漏內(nèi)存。

副作用和外部狀態(tài)

如果一個動作在其發(fā)生的范圍之外產(chǎn)生影響,我們稱之為一方副作用。更改函數(shù)外部的變量,打印到控制臺或更新數(shù)據(jù)庫中的值,這些都是副作用。例如改變函數(shù)內(nèi)部的變量是安全的,但是如果該變量超出了我們函數(shù)的范圍,那么其他函數(shù)也可以改變它的值,這就意味著這個功能不再受控制,因為你無法預(yù)測外部會對這個變量作何操作。所以我們需要跟蹤它,添加檢查以確保它的變化符合我們的預(yù)期。但是這樣子添加的代碼其實與我們程序無關(guān),確增加程序的復(fù)雜度也更容易出錯。雖然副作用總是會有的,但是我們應(yīng)該努力減少。這在響應(yīng)式編程中尤其重要,因為我們隨著時間變換會產(chǎn)生很多狀態(tài)片段。所以避免外部狀態(tài)和副作用是貫穿本書一條宗旨。

我們設(shè)法滿足了我們的簡單要求,但是為了實現(xiàn)這樣一個簡單的目標(biāo),最終得到了相當(dāng)復(fù)雜的代碼。對于首次查看它的開發(fā)人員來說,不容易懂且維護(hù)代碼很困難。 更重要的是,因為我們?nèi)匀恍枰4嫱獠孔菜晕覀兒苋菀自谖磥戆l(fā)展出玄妙的錯誤。

在這種情況下我們想要的只是查詢點擊的“數(shù)據(jù)庫”。如果我們是使用關(guān)系數(shù)據(jù)庫,我們使用聲明性語言SQL:

SELECT x, y FROM clicks LIMIT 10

如果我們將點擊事件流視為可以查詢和轉(zhuǎn)變的數(shù)據(jù)源,該怎么辦?畢竟,它與數(shù)據(jù)庫沒有什么不同,都是一個可以處理數(shù)據(jù)的東西。我們所需要的只是一個為我們提供抽象概念的數(shù)據(jù)類型。

輸入RxJS及其Observable數(shù)據(jù)類型:

Rx.Observable.fromEvent(document, "click")
    .filter(function(c) { return c.clientX > window.innerWidth / 2; })
    .take(10)
    .subscribe(function(c) { console.log(c.clientX, c.clientY) })

這段代碼功能同之前,它可以這樣子解讀:

創(chuàng)建一個Observable的點擊事件,并過濾掉在點擊事件上發(fā)生屏幕左側(cè)的點擊。然后只在控制臺打印前10次點擊的坐標(biāo)。

注意即使您不熟悉代碼也很容易閱讀,也沒有必要創(chuàng)建外部變量來保持狀態(tài)。這樣使我們的代碼是自包含的,不容易產(chǎn)生bug。所以也就沒必要去清除你的狀態(tài)。我們可以合并,轉(zhuǎn)換或者單純的傳遞Observables。我們已經(jīng)將不容易處理的事件轉(zhuǎn)變?yōu)橛行螖?shù)據(jù)結(jié)構(gòu),這種數(shù)據(jù)結(jié)構(gòu)與數(shù)組一樣易于使用,但更加靈活。

在下一節(jié),我們將看到使Observables如此強(qiáng)大的原理。

觀察者和迭代者

要了解Observable的來源,我們需要查看他們的基礎(chǔ):Observer和Iterator軟件模式。在本節(jié)中我們將快速瀏覽它們,然后我們將看到Observables如何結(jié)合,簡單而有力。

觀察者模式

對于軟件開發(fā)人員來說,很難不聽到Observables就想起觀察者模式。在其中我們有一個名為Producer的對象,內(nèi)部保留訂閱者的列表。當(dāng)Producer對象發(fā)生改變時,訂閱者的update方法會被自動調(diào)用。(在觀察者模式的大部分解釋中,這個實體被叫做Subject,為了避免大家和RxJs的自己Subject混淆,我們稱它為Producer)。

ch1/observer_pattern.js

function Producer() {
    this.listeners = [];
}

Producer.prototype.add = function(listener) {
    this.listeners.push(listener);
};

Producer.prototype.remove = function(listener) {
    var index = this.listeners.indexOf(listener);
    this.listeners.splice(index, 1);
};

Producer.prototype.notify = function(message) {
    this.listeners.forEach(function(listener) {
        listener.update(message);
    });
};

Producer對象在實例的偵聽器中保留一個動態(tài)的Listener列表,每當(dāng)Producer更新的時候都會調(diào)用其notify方法。在下面的代碼中,我們創(chuàng)建了兩個對象來監(jiān)聽
notifie,一個Producer的實例。

ch1/observer_pattern.js

// Any object with an "update" method would work.
var listener1 = {
    update: function(message) {
    console.log("Listener 1 received:", message);
}
};
var listener2 = {
    update: function(message) {
    console.log("Listener 2 received:", message);
}
};
var notifier = new Producer();
notifier.add(listener1);
notifier.add(listener2);
notifier.notify("Hello there!");

當(dāng)我們運(yùn)行這個程序的時候:

Listener 1 received: Hello there!
Listener 2 received: Hello there!

當(dāng)notifier更新內(nèi)部狀態(tài)的時候,listener1listener2都會被更新。這些都不需要我們?nèi)ゲ傩摹?/p>

我們的實現(xiàn)很簡單,但它說明了觀察者模式允許觀察者和監(jiān)聽器解耦。

迭代器模式

Observable的另一主要部分來自Iterator模式。一個Iterator是一個為消費者提供簡單的遍象它內(nèi)容的方式,隱藏了消費者內(nèi)部的實現(xiàn)。

Iterator接口很簡單。它只需要兩個方法:next()來獲取序列中的下一個項目,以及hasNext()來檢查是否還有項目序列。

下面是我們?nèi)绾尉帉懸粋€對數(shù)字?jǐn)?shù)組進(jìn)行操作的迭代器,并且只返回divisor參數(shù)的倍數(shù)的元素:

ch1/iterator.js

function iterateOnMultiples(arr, divisor) {
    this.cursor = 0;
    this.array = arr;
    this.divisor = divisor || 1;
}
iterateOnMultiples.prototype.next = function() {
    while (this.cursor < this.array.length) {
    var value = this.array[this.cursor++];
    if (value % this.divisor === 0) {
        return value;
    }
}
};
iterateOnMultiples.prototype.hasNext = function() {
    var cur = this.cursor;
    while (cur < this.array.length) {
        if (this.array[cur++] % this.divisor === 0) {
            return true;
        }
    }
    return false;
};

我們可以這樣子使用我們的迭代器:

ch1/iterator.js

var consumer = new iterateOnMultiples([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3);

console.log(consumer.next(), consumer.hasNext()); // 3 true
console.log(consumer.next(), consumer.hasNext()); // 6 true
console.log(consumer.next(), consumer.hasNext()); // 9 false

迭代器非常適合封裝任何類型數(shù)據(jù)結(jié)構(gòu)的遍歷邏輯。 正如我們在前面的例子中看到的那樣,迭代器在處理不同類型的數(shù)據(jù)的時候就會變得很有趣,或者在運(yùn)行的時候做配置,就像我們在帶有divisor參數(shù)的示例中所做的那樣。

Rx模式和Observable

雖然Observer和Iterator模式本身就很強(qiáng)大,但是兩者的結(jié)合甚至更好。 我們稱之為Rx模式,命名為
在Reactive Extensions庫之后。我們將在本書的其余部分使用這種模式。

Observable序列或簡單的Observable是Rx模式的核心。Observable按順序傳遞出來它的值 - 就像迭代器一樣 - 而不是消費者要求它傳出來的值。這個和觀察者模式有相同之處:得到數(shù)據(jù)并將它們推送到監(jiān)聽器。

pull和push

在編程中,基于推送的行為意味著應(yīng)用程序的服務(wù)器組件向其客戶端發(fā)送更新,而不是客戶端必須輪詢服務(wù)器以獲取這些更新。這就像是說“不要打電話給我們; 我們會打電話給你。“
RxJS是基于推送的,因此事件源(Observable)將推動新值給消費者(觀察者),消費者卻不能去主動請求新值。

更簡單地說,Observable是一個隨著時間的推移可以使用其數(shù)據(jù)的序列。Observables,也就是Observers的消費者相當(dāng)于觀察者模式中的監(jiān)聽器。當(dāng)Observe訂閱一個Observable時,它將在序列中接收到它們可用的值,而不必主動請求它們。

到目前為止,似乎與傳統(tǒng)觀察者沒有太大區(qū)別。 但實際上有兩個本質(zhì)區(qū)別:

Observable在至少有一個Observer訂閱它之前不會啟動。

與迭代器一樣,Observable可以在序列完成時發(fā)出信號。

使用Observables,我們可以聲明如何對它們發(fā)出的元素序列做出反應(yīng),而不是對單個項目做出反應(yīng)。我們可以有效地復(fù)制,轉(zhuǎn)換和查詢序列,這些操作將應(yīng)用于序列的所有元素。

創(chuàng)建Observables

有幾種方法可以創(chuàng)建Observable,創(chuàng)建函數(shù)是最明顯的一種。 Rx.Observable對象中的create方法接受一個Observer參數(shù)的回調(diào)。 該函數(shù)定義了Observable將如何傳出值。這是我們?nèi)绾蝿?chuàng)建一個簡單的Observable:

var observable = Rx.Observable.create(function(observer) {
    observer.onNext("Simon");
    observer.onNext("Jen");
    observer.onNext("Sergi");
    observer.onCompleted(); // We are done
});

當(dāng)我們訂閱此Observable時,它通過在其偵聽器上調(diào)用onNext方法來發(fā)出三個字符串。 然后它調(diào)用onCompleted來表示序列已完成。 但是我們究竟如何訂閱Observable呢?我們使用Observers來做這件事情。

第一次接觸Observers

Observers監(jiān)聽Observables。每當(dāng)Observable中觸發(fā)一個事件,它都會在所有Observers中調(diào)用相關(guān)的方法。

Observers有三種方法:onNext,onCompletedonError

onNext????相當(dāng)于觀察者模式中的update。 當(dāng)Observable發(fā)出新值時調(diào)用它。請注意該名稱如何反映我們訂閱序列的事實,而不僅僅是離散值。

onCompleted????表示沒有更多可用數(shù)據(jù)。 調(diào)用onCompleted后,對onNext的進(jìn)一步調(diào)用將不起作用。

onError????在Observable中發(fā)生錯誤時調(diào)用。 在調(diào)用之后,對onNext的進(jìn)一步調(diào)用將不起作用

以下是我們創(chuàng)建基本觀察者的方法:

var observer = Rx.Observer.create(
    function onNext(x) { console.log("Next: " + x); },
    function onError(err) { console.log("Error: " + err); },
    function onCompleted() { console.log("Completed"); }
);

Rx.Observer對象中的create方法接受onNext,onCompleted和onError情況的函數(shù),并返回一個Observer實例。這三個函數(shù)是可選的,您可以決定要包含哪些函數(shù)。例如,如果我們訂閱無限序列(例如點擊按鈕(用戶可以永久點擊)),則永遠(yuǎn)不會調(diào)用onCompleted處理程序。 如果我們確信序列不能出錯(例如,通過從數(shù)組中生成一個Observable),我們就不需要onError方法了。

使用Observable進(jìn)行Ajax調(diào)用

我們還沒有對Observables做過任何實用的事情。如何創(chuàng)建一個檢索遠(yuǎn)程內(nèi)容的Observable?為此,我們將使用Rx.Observable.create包裝XMLHttpRequest對象。

function get(url) {
    return rxjs.Observable.create(function(observer) {
        // Make a traditional Ajax request
        var req = new XMLHttpRequest(); req.open("GET", url);
        req.onload = function() { 
            if (req.status == 200) {
                // If the status is 200, meaning there have been no problems,     
                // Yield the result to listeners and complete the sequence     
                observer.next(req.response);
                observer.completed();
            }
            else {
                // Otherwise, signal to listeners that there has been an error
                observer.error(new Error(req.statusText)); }
            };
            req.onerror = function() {
            observer.error(new Error("Unknown Error"));
        };
        req.send();
    });
}
// Create an Ajax Observable
var test = get("/api/contents.json");

在前面的代碼中,get函數(shù)使用create來包裝XMLHttpRequest。如果HTTP GET請求成功,我們emit它的內(nèi)容并結(jié)束序列(我們的Observable只會發(fā)出一個結(jié)果)。 否則,我們會emit一個錯誤。在最后一行,我們傳入一個url進(jìn)行調(diào)用。 這將創(chuàng)建Observable,但它不會發(fā)出任何請求。這很重要:Observable在至少有一個觀察者描述它們之前不會做任何事情。 所以讓我們要這樣子做:

// Subscribe an Observer to it
test.subscribe(
    function onNext(x) { console.log("Result: " + x); }, 
    function onError(err) { console.log("Error: " + err); }, 
    function onCompleted() { console.log("Completed"); }
);

首先要注意的是,我們沒有像之前的代碼那樣顯式創(chuàng)建Observer。大多數(shù)時候我們都會使用這個更短的版本,我們在Observable中使用這三個訂閱Observer案例的函數(shù):next,completed和error。

subscribe然后一切就緒。在subscribe之前,我們只是聲明了Observable和Observer將如何交互。只有當(dāng)我們調(diào)用subscribe方法時,一切才開始運(yùn)行。

始終會有一個Operator

在RxJS中,轉(zhuǎn)換或查詢序列的方法稱為Operator。Operator位于靜態(tài)Rx.Observable對象和Observable實例中。在我們的示例中,create就是一個這樣的Operator。

當(dāng)我們必須創(chuàng)建一個非常具體的Observable時,create是一個很好的選擇,但是RxJS提供了許多其他Operator,可以很容易地為常用源創(chuàng)建Observable。

讓我們再看看前面的例子。對于像Ajax請求這樣的常見操作,通常有一個Operator可供我們使用。 在這種情況下,RxJS DOM庫提供了幾種從DOM相關(guān)源創(chuàng)建Observable的方法。由于我們正在執(zhí)行GET請求,我們可以使用Rx.DOM.Request.get,然后我們的代碼就變成了這個:

Rx.DOM.get("/api/contents.json").subscribe(
    function onNext(data) { console.log(data.response); }, 
    function onError(err) { console.error(err); }
);

rxjs-dom本身支持的rxjs版本比較舊,例子只能做為示意

這段代碼與我們之前的代碼完全相同,但我們不必創(chuàng)建XMLHttpRequest的包裝器: 它已經(jīng)存在了。另請注意,這次我們省略了onCompleted回調(diào),因為我們不打算在Observable complete時做出反應(yīng)。我們知道它只會產(chǎn)生一個結(jié)果,我們已經(jīng)在onNext回調(diào)中使用它了。

在本書中我們將使用這樣的大量便利操作符。這都是基于rxjs本身的能量,這也正式rxjs強(qiáng)大的地方之一。

一種可以約束全部的數(shù)據(jù)類型

在RxJS程序中,我們應(yīng)該努力將所有數(shù)據(jù)都放在Observables中,而不僅僅是來自異步源的數(shù)據(jù)。 這樣做可以很容易地組合來自不同來源的數(shù)據(jù),例如現(xiàn)有數(shù)組與回調(diào)結(jié)果,或者XMLHttpRequest的結(jié)果與用戶觸發(fā)的某些事件。

例如,如果我們有一個數(shù)組,其項目需要與來自其他地方的數(shù)據(jù)結(jié)合使用,最好將此數(shù)組轉(zhuǎn)換為Observable。(顯然,如果數(shù)組只是一個不需要組合的中間變量,則沒有必要這樣做。)在本書中,您將了解在哪些情況下值得將數(shù)據(jù)類型轉(zhuǎn)換為Observables。

RxJS為operators提供了從大多數(shù)JavaScript數(shù)據(jù)類型創(chuàng)建Observable的功能。 讓我們回顧一下你將一直使用的最常見的:數(shù)組,事件和回調(diào)。

從數(shù)組創(chuàng)建Observable

我們可以使用通用的operators將任何類似數(shù)組或可迭代的對象轉(zhuǎn)換為Observable。 from將數(shù)組作為參數(shù)并返回一個包含他所有元素的Observable。

Rx.Observable
.from(["Adrià", "Jen", "Sergi"]) 
.subscribe(
    function(x) { console.log("Next: " + x); }, 
    function(err) { console.log("Error:", err); },
    function() { console.log("Completed"); }
);

from是和fromEvent一起,是RxJS代碼中最方便和最常用的operators之一。

從JavaScript事件創(chuàng)建Observable

當(dāng)我們將一個事件轉(zhuǎn)換為一個Observable時,它就變成了一個可以組合和傳遞的第一類值。 例如,這是一個Observable,只要它移動就會傳初鼠標(biāo)指針的坐標(biāo)。

var allMoves = Rx.Observable.fromEvent(document, "mousemove")

allMoves.subscribe(function(e) {
  console.log(e.clientX, e.clientY);
});

將事件轉(zhuǎn)換為Observable會將事件從之前的事件邏輯中釋放出來。更重要的是,我們可以基于原始的Observables創(chuàng)建新的Observable。這些新的是獨立的,可用于不同的任務(wù)。

var movesOnTheRight = allMoves.filter(function(e) { 
    return e.clientX > window.innerWidth / 2;
});
var movesOnTheLeft = allMoves.filter(function(e) { 
    return e.clientX < window.innerWidth / 2;
});
movesOnTheRight.subscribe(function(e) { 
    console.log("Mouse is on the right:", e.clientX);
});
movesOnTheLeft.subscribe(function(e) { 
    console.log("Mouse is on the left:", e.clientX);
});

在前面的代碼中,我們從原始的allMoves中創(chuàng)建了兩個Observable。 這些專門的Observable只包含原始的過濾項:movesOnTheRight包含發(fā)生在屏幕右側(cè)的鼠標(biāo)事件,movesOnTheLeft包含發(fā)生在左側(cè)的鼠標(biāo)事件。 它們都沒有修改原始的Observable:allMoves將繼續(xù)發(fā)出所有鼠標(biāo)移動。 Observable是不可變的,每個應(yīng)用于它們的operator都會創(chuàng)建一個新的Observable。

從回調(diào)函數(shù)創(chuàng)建Observable

如果您使用第三方JavaScript庫,則可能需要與基于回調(diào)的代碼進(jìn)行交互。 我們可以使用fromCallbackfromNodeCallback兩個函數(shù)將回調(diào)轉(zhuǎn)換為Observable。Node.js遵循的是在回調(diào)函數(shù)的第一個參數(shù)傳入錯誤對象,表明存在問題。然后我們使用fromNodeCallback專門從Node.js樣式的回調(diào)中創(chuàng)建Observable:

var Rx = require("rx"); // Load RxJS
var fs = require("fs"); // Load Node.js Filesystem module
// Create an Observable from the readdir method
var readdir = Rx.Observable.fromNodeCallback(fs.readdir); // Send a delayed message
var source = readdir("/Users/sergi");
var subscription = source.subscribe(
    function(res) { console.log("List of directories: " + res);},
    function(err) { console.log("Error: " + err); },
    function() { console.log("Done!"); 
});

前面的代碼中,我們使用Node.js的fs.readdir方法創(chuàng)建一個Observable readdir。 fs.readdir接受目錄路徑和回調(diào)函數(shù)delayedMsg,該函數(shù)在檢索目錄內(nèi)容后調(diào)用。

我們使用readdir和我們傳遞給原始fs.readdir的相同參數(shù),省掉了回調(diào)函數(shù)。 這將返回一個Observable,當(dāng)我們訂閱一個Observer時,它將正確使用onNext,onError和onCompleted。

總結(jié)

在本章中,我們探討了響應(yīng)式編程,并了解了RxJS如何通過Observable解決其他問題的方法,例如callback或promise。現(xiàn)在您了解為什么Observables功能強(qiáng)大,并且您知道如何創(chuàng)建它們。有了這個基礎(chǔ),我們現(xiàn)在可以繼續(xù)創(chuàng)建更有趣的響應(yīng)式程序。下一章將向您展示如何創(chuàng)建和組合基于序列的程序,這些程序為Web開發(fā)中的一些常見場景提供了更“可觀察”的方法。

關(guān)注我的微信公眾號,更多優(yōu)質(zhì)文章定時推送

創(chuàng)建了一個程序員交流微信群,大家進(jìn)群交流IT技術(shù)

如果已過期,可以添加博主微信號15706211347,拉你進(jìn)群

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/96821.html

相關(guān)文章

  • 響應(yīng)編程的思維藝術(shù)】 (1)Rxjs專題學(xué)習(xí)計劃

    摘要:由于技術(shù)棧的學(xué)習(xí),筆者需要在原來函數(shù)式編程知識的基礎(chǔ)上,學(xué)習(xí)的使用。筆者在社區(qū)發(fā)現(xiàn)了一個非常高質(zhì)量的響應(yīng)式編程系列教程共篇,從基礎(chǔ)概念到實際應(yīng)用講解的非常詳細(xì),有大量直觀的大理石圖來輔助理解流的處理,對培養(yǎng)響應(yīng)式編程的思維方式有很大幫助。 showImg(https://segmentfault.com/img/bVus8n); [TOC] 一. 響應(yīng)式編程 響應(yīng)式編程,也稱為流式編程...

    lscho 評論0 收藏0
  • Rxjs 響應(yīng)編程-第五章 使用Schedulers管理時間

    摘要:響應(yīng)式編程第一章響應(yīng)式響應(yīng)式編程第二章序列的深入研究響應(yīng)式編程第三章構(gòu)建并發(fā)程序響應(yīng)式編程第四章構(gòu)建完整的應(yīng)用程序響應(yīng)式編程第五章使用管理時間響應(yīng)式編程第六章使用的響應(yīng)式應(yīng)用程序使用管理時間自從接觸,就開始在我的項目中使用它。 Rxjs 響應(yīng)式編程-第一章:響應(yīng)式Rxjs 響應(yīng)式編程-第二章:序列的深入研究Rxjs 響應(yīng)式編程-第三章: 構(gòu)建并發(fā)程序Rxjs 響應(yīng)式編程-第四章 構(gòu)建完...

    qingshanli1988 評論0 收藏0
  • 響應(yīng)編程的思維藝術(shù)】 (2)響應(yīng)Vs面向?qū)ο?/b>

    摘要:本文是響應(yīng)式編程第一章響應(yīng)式這篇文章的學(xué)習(xí)筆記。通過代碼對比可以發(fā)現(xiàn),在響應(yīng)式編程中,我們不再用對象的概念來對現(xiàn)實世界進(jìn)行建模,而是使用流的思想對信息進(jìn)行拆分和聚合。 本文是Rxjs 響應(yīng)式編程-第一章:響應(yīng)式這篇文章的學(xué)習(xí)筆記。示例代碼地址:【示例代碼】 更多文章:【《大史住在大前端》博文集目錄】 showImg(https://segmentfault.com/img/bVbuE...

    Tonny 評論0 收藏0
  • Rxjs 響應(yīng)編程-第二章:序列的深入研究

    摘要:接下來,我們將實現(xiàn)一個真實的應(yīng)用程序,顯示幾乎實時發(fā)生的地震。得到的由表示,其中包含和的合并元素。如果不同同時傳出元素,合并序列中這些元素的順序是隨機(jī)的。是操作序列的強(qiáng)大操作符。但是的方法仍在運(yùn)行,表明取消并不會取消關(guān)聯(lián)的。 Rxjs 響應(yīng)式編程-第一章:響應(yīng)式Rxjs 響應(yīng)式編程-第二章:序列的深入研究Rxjs 響應(yīng)式編程-第三章: 構(gòu)建并發(fā)程序Rxjs 響應(yīng)式編程-第四章 構(gòu)建完整...

    姘擱『 評論0 收藏0
  • 從命令響應(yīng)(六)

    摘要:從這個系列的第一章開始到第五章,基于的響應(yīng)式編程的基礎(chǔ)知識基本上就介紹完了,當(dāng)然有很多知識點沒有提到,比如,等,不是他們不重要,而是礙于時間精力等原因沒辦法一一詳細(xì)介紹。 從這個系列的第一章開始到第五章,基于rxjs的響應(yīng)式編程的基礎(chǔ)知識基本上就介紹完了,當(dāng)然有很多知識點沒有提到,比如 Scheduler, behaviorSubject,replaySubject等,不是他們不重要,...

    sanyang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<