RxJS 入門

RxJS 是什么

Reactive Programming(響應(yīng)式編程) 是使用異步數(shù)據(jù)流進(jìn)行編程的技術(shù),簡(jiǎn)稱 RP。隨著時(shí)間的推移,產(chǎn)生的一系列事件(鼠標(biāo)點(diǎn)擊、鍵盤輸入等)或數(shù)據(jù)組成的集合,稱為流。RP 就是對(duì)流進(jìn)行編程。RP 本質(zhì)上一種觀察者模式。

RxJS 是 RP 的一種實(shí)現(xiàn)。

Rxjs 有強(qiáng)大的數(shù)據(jù)流組合與控制能力和優(yōu)雅的編碼體驗(yàn),但很難入門。我們來看幾個(gè) Demo 體驗(yàn)下。

1 按鈕只能被點(diǎn)擊一次。
RxJS 的實(shí)現(xiàn)如下
HTML

<button id="sign-in-btn">簽到</button>

JavaScript

var signInBtn = document.querySelector('#sign-in-btn')
Rx.Observable.fromEvent(signInBtn, 'click')
  .take(1)// 1次事件后停止事件流
  .subscribe(()=> {
    signInBtn.textContent = '已簽到'
  })

2 模擬三擊事件。
RxJS 的實(shí)現(xiàn)如下
HTML

<button id="triple-click-btn">三擊</button>

JavaScript

var tripleClickBtn = document.querySelector('#triple-click-btn')
Rx.Observable.fromEvent(tripleClickBtn, 'click')
  .bufferTime(500) // 收集500ms內(nèi)的點(diǎn)擊事件
  .filter(list => list.length === 3)
  .subscribe(()=> {
    console.log('三擊')
  })

3 停止輸入后,如果輸入框內(nèi)容超過2個(gè)字符,觸發(fā)搜索。
RxJS 的實(shí)現(xiàn)如下
HTML

<input type="text" id="input">

JavaScript

Rx.Observable.fromEvent(input, 'keyup')
  .debounceTime(500)// 停止輸入 500ms 后觸發(fā)
  .map(event => event.target.value) // 輸入框中的值
  .filter(value => value.length > 2) // 內(nèi)容超過2個(gè)字符
  .switchMap(調(diào)后臺(tái)搜索接口,返回Promise對(duì)象)
  .subscribe(data=> {
    // 渲染數(shù)據(jù)
  })

當(dāng)然,RxJS 也能對(duì)非異步的數(shù)據(jù)進(jìn)行編程。如,找出數(shù)組中偶數(shù)的個(gè)數(shù)
RxJS 的實(shí)現(xiàn)如下:

Rx.Observable.from([1,2,3,4,5])
  .filter(num => num % 2 === 0)
  .count()
  .subscribe(val => {
    console.log(`偶數(shù)的個(gè)數(shù)有${val}個(gè)`)
  })

概念介紹

可觀察對(duì)象(Observable)

可觀察對(duì)象是多個(gè)值的惰性推送集合。

RxJS 的所有操作都是基于可觀察對(duì)象的。因此,用 RxJs 首先要?jiǎng)?chuàng)建或?qū)?duì)象轉(zhuǎn)化成可觀察對(duì)象。如

Rx.Observable.fromEvent('button', 'click')

上面的代碼將按鈕的點(diǎn)擊事件轉(zhuǎn)化成可觀察對(duì)象。每次按鈕被點(diǎn)擊,可觀察對(duì)象都會(huì)推送該點(diǎn)擊事件。

我們也可以創(chuàng)建一個(gè)可觀察對(duì)象

var observable = Rx.Observable.create(function (observer) {
  try {
    observer.next(1)
    observer.next(2)
  } catch(error) {
    observer.error(error)
  }
  setTimeout(() => {
    observer.next(3)
    observer.complete()
  }, 1000)
})

上面的代碼中,調(diào)用 observer.next 來推送值,可以同步或異步的推值。

可觀察對(duì)象可發(fā)送三種類型的通知

  1. "Next" 通知。寫法: observer.next(數(shù)據(jù))。
  2. "Error" 通知, 發(fā)送一個(gè) JavaScript 錯(cuò)誤 或 異常。寫法: observer.error(錯(cuò)誤對(duì)象)
  3. "Complete" 通知: 不再發(fā)送任何值。寫法:observer.complete()

可觀察對(duì)象可以發(fā)送任意數(shù)量的 "Next" 類型的通知,但只能發(fā)送一次 "Error" 或 "Complete" 類型的通知。如果發(fā)送了 "Error" 或 "Complete" 通知的話,之后不會(huì)再發(fā)送任何通知了。

觀察者(Observer)

觀察者是可觀察對(duì)象發(fā)送的值的消費(fèi)者。

觀察者只是一組回調(diào)函數(shù)的集合,每個(gè)回調(diào)函數(shù)對(duì)應(yīng)一種可觀察對(duì)象發(fā)送的通知類型。

var observer = {
  next: x => console.log('Observer got a next value: ' + x),
  error: err => console.error('Observer got an error: ' + err),
  complete: () => console.log('Observer got a complete notification'),
}

observable.subscribe(observer)

如果觀察者只在乎可觀察對(duì)象發(fā)送的 Next 通知,可以簡(jiǎn)寫為:

observable.subscribe(x => console.log('Observer got a next value: ' + x))

訂閱(Subscription)

訂閱表示可清理資源的對(duì)象。

當(dāng)觀察者不需要再消費(fèi)可觀察對(duì)象推送的值時(shí),可調(diào)用訂閱對(duì)象上的unsubscribe 函數(shù)來取消訂閱和釋放資源。如

var subscription = observable.subscribe(x => console.log(x));

subscription.unsubscribe() // 取消訂閱

主體(Subject)

主體是一種特殊的可觀察對(duì)象。

主題與普通的可觀察對(duì)象的區(qū)別點(diǎn)在與

  • 允許值被多播到多個(gè)觀察者。普通的可觀察者對(duì)象是單播的(僅給一個(gè)的觀察者發(fā)送通知)。
  • 可以推送值:擁有next()/error()/complete()方法。

單播的可觀察對(duì)象也可以轉(zhuǎn)化成多播的對(duì)象。如

var source=Rx.Observable.from([1,2,3]);
var subject=new Rx.Subject();
var multicasted=source.multicast(subject);

RxJS 中還有些特殊的主體,如 BehaviorSubjectReplaySubject,AsyncSubject。感興趣的可以了解下。

操作符

操作符是可觀察對(duì)象上的方法。

可觀察對(duì)象上執(zhí)行操作符,并不會(huì)改變可觀察對(duì)象,而是生產(chǎn)一個(gè)新的可觀察對(duì)象。操作符本質(zhì)上是一個(gè)將某個(gè)可觀察對(duì)象作為輸入然后輸出另一個(gè)可觀察對(duì)象的純函數(shù)。

RxJS 有一大堆操作符,如此強(qiáng)大的原因正是源自于它的操作符。感興趣的可以過一遍RxJS操作符文檔。

Marble diagrams可以方便的懂操作符的意思,如下圖

詳情見這里

調(diào)度器(Scheduler)

調(diào)度器控制著何時(shí)啟動(dòng)可觀察對(duì)象和何時(shí)發(fā)送通知。

詳情見這里。

優(yōu)勢(shì)

容易寫出簡(jiǎn)潔的函數(shù)式編程的代碼。函數(shù)式編程的是一大優(yōu)點(diǎn)是無副作用:不會(huì)修改函數(shù)外部的值,讓你的代碼更健壯,不容易出錯(cuò)。

使用場(chǎng)景

  • 處理多個(gè)數(shù)據(jù)序列(有一定順序)。
  • 多個(gè)復(fù)雜的異步或者事件組合在一起。

在 Vue.js 中使用RxJS

以模擬三擊事件,舉例,Vue.js 中這么寫:
HTML

<div id="app">
  <button @click="clickIt">三擊</button>
</div>

JavaScript

new Vue({
  el: '#app',
  data: {
    clickSubject: null
  },
  methods: {
    clickIt($event) {
      this.clickSubject.next()
    }
  },
  mounted() {
    this.clickSubject = new Rx.Subject()
    this.clickSubject
      .bufferTime(500)
      .filter(list => list.length === 3)
      .subscribe(()=> {
        console.log('三擊')
      })
  }
})

也可以嘗試用 vue-rx

文檔

推薦閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文轉(zhuǎn)自我的博客閱讀原文。 概況 Rxjs是響應(yīng)式編程思想在JS中的一種實(shí)現(xiàn)。那么Rxjs到底是個(gè)什么東西呢?裝逼...
    xuan241閱讀 775評(píng)論 0 0
  • 一.背景介紹 Rx(Reactive Extension -- 響應(yīng)式擴(kuò)展 http://reactivex.io...
    愛上Shu的小刺猬閱讀 2,191評(píng)論 1 3
  • 該系列教程建立在有一定promise知識(shí)的前端同學(xué)身上,因?yàn)楸容^抽象,我們?cè)诶又姓撟C說明。eg1. 關(guān)鍵字 Ob...
    我是上帝可愛多閱讀 3,462評(píng)論 0 3
  • 操作異步事件,一般可以用callback或是promise來達(dá)成,然而promise主要設(shè)計(jì)于一次性的事件與單一回...
    冰果2016閱讀 551評(píng)論 0 0
  • 介紹 RxJS是一個(gè)異步編程的庫,同時(shí)它通過observable序列來實(shí)現(xiàn)基于事件的編程。它提供了一個(gè)核心的類型:...
    泓滎閱讀 16,779評(píng)論 0 12

友情鏈接更多精彩內(nèi)容