1. 程式人生 > 其它 >promise 和 Observable 的區別

promise 和 Observable 的區別

StackOverflow 上的討論:What is the difference between Promises and Observables?

得贊最高的一個回答:1777 贊

當非同步操作完成或失敗時,Promise 會處理單個事件。

注意:有 Promise 庫支援 cancellation 操作,但 ES6 Promise 到目前為止還不支援。

Observable

一個 Observable 就像一個 Stream(在許多語言中),允許傳遞零個或多個事件,其中為每個事件呼叫回撥。

通常 Observable 比 Promise 更受歡迎,因為它提供了 Promise 的特性等等。使用 Observable,您是否要處理 0、1 或多個事件並不重要。您可以在每種情況下使用相同的 API。

Observable 還比 Promise 具有可取消的優勢。如果不再需要對伺服器的 HTTP 請求或其他一些昂貴的非同步操作的結果,Observable 的訂閱允許取消訂閱,而 Promise 最終會呼叫成功或失敗的回撥,即使你不這樣做不再需要通知或它提供的結果。

雖然 Promise 會立即啟動,但 Observable 只有在您訂閱它時才會啟動。這就是為什麼 Observable 被稱為懶惰的原因。

Observable 提供了 map、forEach、reduce 等運算子,用法類似於陣列。

還有一些強大的操作符,如 retry() 或 replay() 等,它們通常非常方便。

延遲執行允許在通過訂閱執行 observable 之前建立一系列操作符,以進行更具宣告性的程式設計。

排名第二的回答:374 贊

舉例說明。

Angular 使用 Rx.js Observables 而不是 promises 來處理 HTTP。

假設您正在構建一個搜尋功能,該功能應在您鍵入時立即顯示結果。 聽起來很熟悉,但這項任務會帶來很多挑戰。

我們不想在使用者每次按下一個鍵時都訪問伺服器端點,如果這樣做的話,伺服器會被大量的 HTTP 請求淹沒。 基本上,我們只想在使用者停止輸入後觸發 HTTP 請求,而不是每次擊鍵時觸發。

對於後續請求,不要使用相同的查詢引數訪問搜尋端點。

處理無序響應。 當我們同時有多個請求進行中時,我們必須考慮它們以意外順序返回的情況。 想象一下,我們首先鍵入 computer,停止,發出請求,然後鍵入 car,停止,發出請求。 現在我們有兩個正在進行的請求。 不幸的是,攜帶結果給computer 的請求在攜帶結果給 car 的請求之後返回。

首先看如何用 promise 實現這個需求。當然,上文提到的所有邊界情況都沒有處理。

wikipedia-service.ts:

import { Injectable } from '@angular/core';
import { URLSearchParams, Jsonp } from '@angular/http';

@Injectable()
export class WikipediaService {
  constructor(private jsonp: Jsonp) {}

  search (term: string) {
    var search = new URLSearchParams()
    search.set('action', 'opensearch');
    search.set('search', term);
    search.set('format', 'json');
    return this.jsonp
                .get('http://en.wikipedia.org/w/api.php?callback=JSONP_CALLBACK', { search })
                .toPromise()
                .then((response) => response.json()[1]);
  }
}

我們正在注入 Jsonp 服務,以使用給定的搜尋詞對 Wikipedia API 發出 GET 請求。 請注意,我們呼叫 toPromise 是為了從 Observable 到 Promise。 最終以 Promise<Array> 作為我們搜尋方法的返回型別。

app.ts 的實現:

// check the plnkr for the full list of imports
import {...} from '...';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Wikipedia Search</h2>
      <input #term type="text" (keyup)="search(term.value)">
      <ul>
        <li *ngFor="let item of items">{{item}}</li>
      </ul>
    </div>
  `
})
export class AppComponent {
  items: Array<string>;

  constructor(private wikipediaService: WikipediaService) {}

  search(term) {
    this.wikipediaService.search(term)
                         .then(items => this.items = items);
  }
}

這裡也沒什麼驚喜。 我們注入我們的 WikipediaService 並通過搜尋方法向模板公開它的功能。 該模板簡單地繫結到 keyup 並呼叫 search(term.value)。

我們解開 WikipediaService 的搜尋方法返回的 Promise 的結果,並將其作為一個簡單的字串陣列公開給模板,這樣我們就可以讓 *ngFor 迴圈遍歷它併為我們構建一個列表。

Where Observables really shine

讓我們更改我們的程式碼,不要在每次擊鍵時敲擊端點,而是僅在使用者停止輸入 400 毫秒時傳送請求

為了揭示這樣的超能力,我們首先需要獲得一個 Observable ,它攜帶使用者輸入的搜尋詞。 我們可以利用 Angular 的 formControl 指令,而不是手動繫結到 keyup 事件。 要使用此指令,我們首先需要將 ReactiveFormsModule 匯入到我們的應用程式模組中。

app.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { JsonpModule } from '@angular/http';
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [BrowserModule, JsonpModule, ReactiveFormsModule]
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

匯入後,我們可以在模板中使用 formControl 並將其設定為名稱“term”。

<input type="text" [formControl]="term"/>

在我們的元件中,我們從@angular/form 建立了一個 FormControl 的例項,並將其公開為元件上名稱 term 下的一個欄位。

在幕後,term 自動公開一個 Observable 作為我們可以訂閱的屬性 valueChanges。 現在我們有了一個 Observable,獲得使用者輸入就像在我們的 Observable 上呼叫 debounceTime(400) 一樣簡單。 這將返回一個新的 Observable,它只會在 400 毫秒內沒有新值出現時才發出新值。

export class App {
  items: Array<string>;
  term = new FormControl();
  constructor(private wikipediaService: WikipediaService) {
    this.term.valueChanges
              .debounceTime(400)        // wait for 400ms pause in events
              .distinctUntilChanged()   // ignore if next search term is same as previous
              .subscribe(term => this.wikipediaService.search(term).then(items => this.items = items));
  }
}

對我們的應用程式已經顯示結果的搜尋詞發出另一個請求將是一種資源浪費。 為了實現所需的行為,我們所要做的就是在我們呼叫 debounceTime(400) 之後立即呼叫 distinctUntilChanged 運算子。

Observable 和 promise 的比較:

更多Jerry的原創文章,盡在:"汪子熙":