Angular 記錄 - Observable 概述

Angular 簡介javascript

Angular 由 google 建立,於 2010 年正式發佈,到目前已經更新到 v8.0 版本。相比於目前煊赫一時的 React 與 Vue 框架來講,Angular 自帶完備的生態系統使其更能被稱之爲一款 「 框架 」.前端

Angular 對 typescript 的完美支持(angular 自己就是由 typescript 去編寫的)以及它對模塊化和層次依賴注入的架構方式,使其在構建微服務前端系統也有必定優點. 此外 Angular 框架中引入 Rxjs(ReactiveX javascript) , 運用 Observable 去解決異步問題,使異步問題變的更加簡單和可控。java


Observable (可觀察對象)

社區對於 Observables, Observable, Observer, Subject, Subscription 等有不少介紹,概念性的知識點很難記憶,我概述了幾條,並記錄順便分享一下本身對這些概念的理解:typescript

(1) Observables是Rx的核心, Rx 是(Reactive Extensions)的簡寫,而 rxjs 則是 Observable 在 Javascript 版本的實現,除了 Rxjs, 還有 RxJava, RxDart, RxSwift 等語言的實現版本。數組

(2) Rxjs 依據 Observable 做爲核心,對可觀察對象 Observable 進行賦能,將其轉換爲操做流,經過 operators 操做符完成對數據流的變換、組合、操縱等。promise

(3) Observable 是一種新的 push 體系(Pull 和 Push 是兩種不一樣的協議,用於描數據的生產者 和 數據消費者之間的聯繫方式)。能夠經過如下例子簡單加以理解:bash

function GetName()
   {
       const name: string = 'i come from a method';
       return name;
   }
   
   const consumerName: string = GetName(); // consumerName 'i come from a method'
複製代碼

JS 經過調用函數或取數據,此時函數是數據的產生者。函數必須被 call 即調用才能夠被觸發,這就是一種 pull(拉取) 體系。微信

那麼在 Rxjs 中:架構

import { Observable } from 'rxjs';
   const NameObservables$: Observable<string> = new Observable(
       subscriber => {
           const name: string = 'i come from a method';
           subscriber.next(name);
       }
   );
   
   NameObservables$.subscribe((name: string) => {
       console.log(name); // 'i come from a method'
   });
   
複製代碼

代碼中,咱們經過 subscribe 來獲取數據,這和直接調用函數有什麼區別呢?app

觀察代碼咱們能夠發現,咱們將函數和消費者以前進行了解耦,咱們只是訂閱了數據生產者返回的NameObservables$這個可觀察對象,這使得咱們在獲取原數據的操做上多了一層隔離,利用這層隔離,咱們能夠作不少事,好比利用各類operators對原數據進行各種操做, 而且咱們對一類數據源進行了必定程度的複用,由於任何須要 name 的地方均可以訂閱這個 Observable。

Observable 區別於普通函數的另外一個特色就是,Observable 能夠異步返回多個值,而且因爲上面提到的隔離,咱們能夠針對不一樣的場景分別去處理這些值,只要訂閱 Observable 對象的訂閱者們,均可以獲取到這些數據。大概像這樣:

import { Observable } from 'rxjs';
   const NameObservables$: Observable<string> = new Observable(
       subscriber => {
           const name: string = 'i come from a method';
           subscriber.next(name);
           const info: any = 'i am happy';
           subscriber.next(info);
           setTimeout(() => {
               const info2: any = 'i like rxjs';
               subscriber.next(info2);
           }, 2000)
       }
   );
   
   NameObservables$.subscribe((name: string) => {
       console.log(name); // 'i come from a method'
       console.log(name); // 'i am happy'
       console.log(name); // delay 2s => 'i like rxjs'
   });
   
複製代碼

(4) 可觀察對象 Observable 本質也是基於 訂閱者模式 的一種應用,一個 Observable 構造函數能夠建立任意類型的觀察流供觀察者(Observer)進行訂閱操做。(訂閱?:也就是獲取數據,能夠簡單理解爲訂閱微信公衆號)。生活中咱們經過關注一個公衆號獲取訂閱通知,在 Observable 的世界裏,則經過 訂閱(subscribe)操做去獲取可觀察對象流轉出來的信息。這個過程當中代碼簡單模擬一下以下:

class Observable {
          constructor(subscribe){
              this.subscriptions = [];
              this._subscribe = subscribe;
          }
          subscribe(observer){
              const _this = this;
              
              this.subscriptions.push(observer);
              this._subscribe.call(this, observer);
              return {
                  unsubscribe: () => {
                      const subscriptionIndex = _this.subscriptions.indexOf(observer);
                      _this.subscriptions.splice(subscriptionIndex, 1);
                  }
              }
      }
  }
  
  let testObservable$ = new Observable(function(observer){
      observer.next(1);
      observer.next(2);
      observer.next(3);
      observer.complete();
  });
  
  const subscription = testObservable$.subscribe({
      next:function(val){ console.log('next', val); },
      error:function(error){ console.log('error', error); },
      complete:function(){ console.log('complete'); }
  });
  // 取消訂閱,再也不接受消息
  setTimeout(() => {
      subscription.unsubscribe();
  }, 2000);
複製代碼

(5) 經過上面的代碼也能夠發現,一個Observer(觀察者) 能獲取到 3 種通知,即 next, error, complete. 當有人訂閱Observable的實例時,須要經過調用 subscribe 方法來獲取到一個 observer對象,subscribe 方法會返回一個 subscription 對象,調用 subscirption 的 unsubscribe 方法, 訂閱者 Observer 就會中止接收通知。原有的Observable對象依然存在。

(6) 結合上面瞭解到的 Observable 特性,咱們能夠對比 Promise體系。熟悉 Promise 的朋友都知道 ,Promise 的 executor 函數接受 resolve, reject 方法,經過調用 resolve 或者 reject 來觸發回調數組,將 resolve 的 data 或者是 reject 的 data 經過回調,返回給 then 方法中的 onFulfilled 函數。Promise 單個體系中,由於這些 value 被回調回去的時間是很是肯定的,因此 promise 也是一種 push 體系, promise 一旦被 resolve 以後便沒法再次返回和取消了,至少他自己不具有取消的能力。下面是 promise 部分簡單的實現:

class Promise {
    constructor(executor) {
        this.status = PENDING;
        this.value = void 0;
        this.err = void 0;
        
        this.fulfilledList = new Array();  // fulfilled sub lists
        this.rejectedList = new Array();   // rejected sub lists

        let resolve = (value) => {
            if (this.status === PENDING) {
                ...
                this.fulfilledList.forEach(cb => cb());
            }
        }

        let reject = (err) => {
            if (this.status === PENDING) {
                ...
                this.rejectedList.forEach(cb => cb());
            }
        }
        
        try {
            executor(resolve, reject);
        } catch (e) {
            reject(e);
        }
    }

    then(onFulfilled, onRejected) {
        let promiseThen = void 0;
        promiseThen = new Promise((resolveNext, rejectNext) => {
            ....
            if (this.status === PENDING) {
                this.fulfilledList.push(() => {
                    ...
                    let result = onFulfilled(this.value);
                    ...
                });
                this.rejectedList.push(() => {
                    ...
                    let result = onRejected(this.err);
                    ...
                });
            }
        });
        return promiseThen;
    }
}
複製代碼

瞭解 Observable 的諸多概念以後,我總結了如下幾點:

(1) Observable 是一種新的 push 體系, 它經過把異步操做封裝成一個能夠自由組合,靈活變化的可觀察對象,來對異步數據流進行控制,是一種高級的 promise。

(2) Observable 是 Rxjs 的核心,真正強大的是 Observable 這種觀察和訂閱模式配合 Rxjs 各種操做符實現對異步流的靈活控制 。

(3) Observable 對比 Promise 擁有可取消,多複用,多值返回, 異步可控等優勢。

(4) Observable 數據源能夠保留,並能夠被多個觀察者使用的特性,使得跨組件的通信變動加簡單。

瞭解了 Observable 的概念及簡單原理,咱們能夠更好的在實際業務場景去使用 Observable 和 Rxjs 。

感謝您的閱讀~

相關文章
相關標籤/搜索