สัญญาและของรางวัลต่างกันอย่างไร


1396

ความแตกต่างระหว่างPromiseและObservableในเชิงมุมคืออะไร?

ตัวอย่างในแต่ละกรณีจะเป็นประโยชน์ในการทำความเข้าใจทั้งสองกรณี ในสถานการณ์ใดที่เราสามารถใช้แต่ละกรณี


23
ฉันขอแนะนำให้คุณอ่านโพสต์นี้ คำสัญญาของ Angular2 เทียบกับที่สังเกตได้
erolkaya84

4
ในแง่ที่ง่ายขึ้นangular-2-training-book.rangle.io/handout/observables/…
Pardeep Jain

3
สำหรับทุกคนที่อ่านคำถาม & คำตอบนี้ - ในฐานะคนที่มีส่วนร่วมในทั้งสองโลกจากผู้ดูแลลำโพงและผู้ใช้ PoV ฉันแนะนำให้คุณอ่านเอกสาร RxJS อย่างเป็นทางการและเอกสาร MDN เกี่ยวกับสัญญา ฉันค้นหาคำตอบที่นี่เป็นการส่วนตัวที่ทำให้เข้าใจผิดและไม่ถูกต้องและเชื่อว่าพวกเขาเป็นในขณะที่มีความตั้งใจดีจากคนที่พยายามจะช่วยเป็นอันตรายมาก
Benjamin Gruenbaum

1
ฉันขอแนะนำให้คุณอ่านเอกสารอย่างเป็นทางการเชิงมุมนี้angular.io/guide/comparing-observables
fgul

และนี่คือเหตุผลว่าทำไมลิงก์จึงถือเป็นคำตอบที่ยอมรับไม่ได้
เดฟ

คำตอบ:


1549

คำมั่นสัญญา

Promiseจัดการกับเหตุการณ์เดียวเมื่อ async เสร็จสมบูรณ์การดำเนินการหรือไม่

หมายเหตุ: มีไลPromiseบรารี่อยู่ด้านนอกซึ่งรองรับการยกเลิก แต่ ES6 Promiseยังอยู่ไม่ถึง

น่าติดตาม

An Observableเป็นเหมือนStream(ในหลายภาษา) และอนุญาตให้ส่งผ่านเหตุการณ์ตั้งแต่ศูนย์หรือมากกว่านั้นซึ่งมีการโทรกลับสำหรับแต่ละเหตุการณ์

มักจะObservableเป็นที่ต้องการมากกว่าPromiseเพราะมันมีคุณสมบัติPromiseและอื่น ๆ ด้วยObservableมันไม่สำคัญว่าคุณต้องการจัดการเหตุการณ์ 0, 1 หรือหลายรายการ คุณสามารถใช้ API เดียวกันในแต่ละกรณี

Observableยังมีข้อได้เปรียบมากกว่าPromiseที่จะยกเลิกได้ หากผลลัพธ์ของการร้องขอ HTTP ไปยังเซิร์ฟเวอร์หรือการดำเนินการ async ที่มีราคาแพงอื่น ๆ ไม่จำเป็นอีกต่อไปSubscriptionการObservableอนุญาตให้ยกเลิกการสมัครในขณะที่ a Promiseจะเรียกสำเร็จหรือโทรกลับล้มเหลวในที่สุดแม้ว่าคุณไม่ต้องการการแจ้งเตือน หรือผลลัพธ์ที่ได้จะให้อีกต่อไป

สังเกตได้ให้ผู้ประกอบการเช่นmap, forEach, reduce... คล้ายกับอาร์เรย์

นอกจากนี้ยังมีผู้ประกอบการที่มีประสิทธิภาพเช่นretry()หรือreplay()... ที่มักจะมีประโยชน์มาก


180
ดังนั้นมีเหตุผลที่ดีที่จะใช้สัญญาแทนที่จะสังเกตได้ในกรณีที่โทรกลับครั้งเดียวหรือควรใช้สังเกตการณ์ที่นั่นเพราะพวกเขาสามารถทำงานได้เช่นกัน? โดยพื้นฐานแล้วเป็นวิธีปฏิบัติที่ดีที่จะ "สังเกตทุกสิ่ง" หรือไม่สัญญายังคงมีอยู่หรือไม่?
Josh Werts

75
ถ้าคุณต้องการที่จะใช้สไตล์ปฏิกิริยาเพียงแค่ใช้สิ่งที่สังเกตได้ทุกที่ หากคุณมีสิ่งที่น่าสังเกตเท่านั้นคุณสามารถเขียนได้อย่างง่ายดาย หากคุณผสมมันไม่สะอาดอีกต่อไป หากคุณไม่สนใจสไตล์การตอบสนองคุณสามารถใช้สัญญาสำหรับกิจกรรมเดี่ยวที่คุณไม่สนใจเกี่ยวกับการยกเลิกและสังเกตได้สำหรับกระแสของกิจกรรม
GünterZöchbauer

35
@ GünterZöchbauerเฮ้ - ฉันไม่มีข้อโต้แย้งกับ Observables หรือการเขียนโปรแกรมการทำงาน ฉันแค่บอกว่าฉันเชื่อว่าผู้คนที่พบเห็น Observables ส่วนใหญ่ผ่าน http ใน NG2 นั้นไม่มีเหตุผลอะไรเลยที่จะใช้ Observables over Promises เพื่อโทรออก พวกเขาสูญเสียอะไรในทางปฏิบัติโดยใช้สัญญา ตัวดำเนินการ debounce และ retry ไม่เกี่ยวข้อง - คุณสามารถ debounce ด้วย ng-debounce และหากการโทรที่คาดว่าจะล้มเหลวโดยทั่วไปจะมีปัญหากับรหัส ครั้งเดียวที่ฉันต้องทำงานกับการลองโทรซ้ำขณะที่กำลังค้นหา API ของบุคคลที่สามที่ไม่เสถียรสำหรับ HVT
VSO

92
แต่โปรดอย่าลืมว่าPromiseพร้อมกับasync/ awaitทำให้รหัสของคุณแบนอีกครั้ง! ในสถานการณ์ส่วนใหญ่และในโครงการที่ไม่เกี่ยวข้องกับวิทยาศาสตร์จรวดไม่จำเป็นต้องเขียนฟังก์ชันซ้อนที่น่ากลัวด้วยวิธีการที่ซับซ้อนโดยไม่จำเป็น คุณสามารถใช้async/ awaitวันนี้กับ transpilers เช่นTypeScriptและเขียนรหัสแบนที่มนุษย์อ่านได้จริงโดยไม่ต้องใช้แผ่นrxjsสำเร็จรูปใด ๆ คุณอาจจะต้องใช้rxjsบางครั้งในบางสถานการณ์เพราะมันมีหลายสิ่งหลายอย่างที่จะนำเสนอ
evilkos

15
คำตอบนี้เป็นความเข้าใจผิดซึ่งเป็นที่สังเกตได้คือไม่เหมือนกระแสมันเป็นเหมือนฟังก์ชั่นที่ให้ผลตอบแทนกระแส
Benjamin Gruenbaum

334

ทั้งสองPromisesและObservablesให้ abstractions ที่ช่วยให้เราจัดการกับธรรมชาติแบบอะซิงโครนัสของแอปพลิเคชันของเรา ความแตกต่างระหว่างพวกเขาถูกชี้อย่างชัดเจนโดย@Günterและ @Relu

เนื่องจากข้อมูลโค้ดมีค่าหนึ่งพันคำให้อ่านตัวอย่างด้านล่างเพื่อทำความเข้าใจได้ง่ายขึ้น

ขอบคุณ @Christoph Burgdorf สำหรับบทความที่ยอดเยี่ยม


Angular ใช้ Rx.js Observables แทนที่จะให้สัญญากับการจัดการกับ HTTP

สมมติว่าคุณกำลังสร้างฟังก์ชั่นการค้นหาที่ควรแสดงผลลัพธ์ทันทีที่คุณพิมพ์ ฟังดูคุ้นเคย แต่มีความท้าทายมากมายที่มาพร้อมกับงานนั้น

  • เราไม่ต้องการโจมตีเซิร์ฟเวอร์ปลายทางทุกครั้งที่ผู้ใช้กดปุ่มมันน่าจะท่วมพวกเขาด้วยพายุHTTPคำขอ โดยพื้นฐานแล้วเราต้องการตีเมื่อผู้ใช้หยุดพิมพ์แทนที่จะกดแป้นทุกครั้ง
  • อย่ากดจุดสิ้นสุดการค้นหาด้วยparams ของแบบสอบถามเดียวกันสำหรับคำขอที่ตามมา
  • จัดการกับการตอบกลับที่ไม่เป็นไปตามคำสั่ง เมื่อเรามีคำขอหลายเที่ยวบินในเวลาเดียวกันเราจะต้องพิจารณากรณีที่พวกเขากลับมาในลำดับที่ไม่คาดคิด ลองจินตนาการว่าเราพิมพ์คอมพิวเตอร์เป็นครั้งแรกหยุดคำขอออกไปเราพิมพ์รถยนต์หยุดขอออกไป ตอนนี้เรามีสองคำขอในเที่ยวบิน แต่น่าเสียดายที่การร้องขอที่ดำเนินการผลสำหรับคอมพิวเตอร์กลับมาหลังจากการร้องขอที่ดำเนินการผลสำหรับรถยนต์

การสาธิตก็จะประกอบด้วยสองไฟล์: และapp.ts wikipedia-service.tsในสถานการณ์โลกแห่งความเป็นจริงเราน่าจะแยกสิ่งต่างๆออกไปอีก


ด้านล่างคือการใช้งานตามสัญญาที่ไม่ได้จัดการกรณีขอบที่อธิบายไว้ใด ๆ

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บริการเพื่อทำการGETร้องขอกับWikipedia APIพร้อมกับข้อความค้นหาที่ระบุ ขอให้สังเกตว่าเราเรียกtoPromiseเพื่อให้ได้รับจากไปObservable<Response> Promise<Response>ในที่สุดท้ายด้วย a Promise<Array<string>>เป็นประเภทส่งคืนของวิธีการค้นหาของเรา

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และแสดงให้เห็นถึงการทำงานของมันผ่านวิธีการค้นหาไปยังเทมเพลต แม่แบบก็ผูกกับkeyupsearch(term.value)และบริการโทร

เราแกะผลลัพธ์ของสัญญาว่าวิธีการค้นหาของ WikipediaService จะส่งคืนและแสดงเป็น Array แบบสตริงที่เรียบง่ายไปยังเทมเพลตเพื่อให้เราสามารถ*ngForวนซ้ำมันและสร้างรายการสำหรับเรา

ดูตัวอย่างของการใช้งานตามสัญญาบนPlunker


จุดสังเกตที่ส่องแสงจริงๆ

ลองเปลี่ยนรหัสของเราเพื่อไม่ใช้จุดปลายกับการกดแป้นทุกครั้ง แต่จะส่งการร้องขอเมื่อผู้ใช้หยุดพิมพ์400 ms

ในการเปิดเผยพลังพิเศษเช่นนี้เราต้องได้รับข้อความObservable<string>ค้นหาที่ผู้ใช้พิมพ์มาก่อนแทนที่จะเชื่อมโยงกับเหตุการณ์คีย์อัพด้วยตนเองเราสามารถใช้ประโยชน์จากformControlคำสั่งของ Angular ในการใช้คำสั่งนี้เราต้องนำเข้า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"/>

ในองค์ประกอบของเราเราสร้างอินสแตนซ์ของFormControlจาก@angular/formและเปิดเผยเป็นฟิลด์ภายใต้ชื่อคำในส่วนประกอบของเรา

เบื้องหลังคำว่า exposes Observable<string>เป็นคุณสมบัติvalueChangesที่เราสามารถสมัครรับข้อมูลโดยอัตโนมัติ ตอนนี้เรามีObservable<string>การเอาชนะผู้ใช้ป้อนเป็นเรื่องง่ายเหมือนการเรียกของเราdebounceTime(400) Observableสิ่งนี้จะคืนค่าใหม่Observable<string>ที่จะปล่อยค่าใหม่เมื่อไม่มีค่าใหม่มาเป็นเวลา 400ms

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

มันจะเป็นการสิ้นเปลืองทรัพยากรในการส่งคำขอใหม่สำหรับคำค้นหาที่แอปของเราแสดงผลลัพธ์แล้ว สิ่งที่เราต้องทำเพื่อให้ได้พฤติกรรมที่ต้องการคือโทรหาdistinctUntilChangedผู้ให้บริการทันทีหลังจากที่เราเรียกdebounceTime(400)

ดูตัวอย่างของการใช้งานที่สังเกตได้บนPlunker

สำหรับการรับมือกับการตอบสนองออกจากการสั่งซื้อโปรดตรวจสอบบทความเต็ม http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html

เท่าที่ฉันกำลังใช้ Http ใน Angular ฉันยอมรับว่าในกรณีการใช้งานปกติมีความแตกต่างไม่มากนักเมื่อใช้ Observable over Promise ไม่มีประโยชน์ใดที่เกี่ยวข้องกับการปฏิบัติจริงที่นี่ หวังว่าฉันจะเห็นกรณีการใช้งานขั้นสูงในอนาคต :)


เรียนรู้เพิ่มเติม


31
ฉันไม่ได้ซื้อการตัดสินใจเปลี่ยน Http service ให้เป็น Observable ทุกคำอธิบายที่ฉันได้ยินขึ้นอยู่กับตัวอย่างเดียวกัน: การค้นหาตามคำ แต่สิ่งนั้นเกี่ยวข้องกับการจัดการเหตุการณ์ของเบราว์เซอร์ ฉันต้องการทราบว่าข้อดีคืออะไรในการนำไปใช้เมื่อจัดการกับคำขอ HTTP แบบอะซิงโครนัส
Alex Pollan

1
เป็นการตัดสินใจโดยไม่ตั้งใจเพื่อหลีกเลี่ยงรูปแบบผสมหรือไม่?
Alex Pollan

6
@AlexPollan จริง ๆ แล้วมีคำอธิบายที่ดีเกี่ยวกับประโยชน์ของบริการ HTTP ที่ส่งคืนการสังเกตบนพ็อดคาสท์นี้กับ Ben Lesh devchat.tv/js-jabber/... ในที่สุดประโยชน์ที่สำคัญคือคุณสามารถยกเลิกการสังเกตและกรณีการใช้งานสำหรับสิ่งที่อธิบายไว้ในลิงค์ด้านบน - ในขณะที่มีการวางแผนเล็กน้อย - คือถ้าคุณโทรไปยัง apis หลายครั้งและสนใจเฉพาะการตอบกลับครั้งแรกเท่านั้น จาก apis ที่คุณโทรติดต่อกลับก่อนจากนั้นคุณสามารถยกเลิกคำขอไปยังผู้อื่นได้
nikolasleblanc

2
@nikolasleblanc ฉันค่อนข้างแน่ใจว่าคุณสามารถใช้ $ q.race () เพื่อสิ่งนั้นได้หรือไม่
jameslouiz

2
@AlexPollan ข้อได้เปรียบคือบริการ HTTP ที่ใช้ Observable ทำให้ง่ายต่อการยกเลิกการร้องขอ HTTP กลางเที่ยวบิน เงื่อนไขการแข่งขันในคำตอบของ trungk18 สามารถแก้ไขได้โดยเพียงยกเลิกการสมัครจาก HTTP ที่สังเกตได้ก่อนที่จะทำการร้องขอในภายหลัง RXJS switchMap สามารถใช้สำหรับการร้องขอ HTTP ที่ถูกทริกเกอร์โดยผู้สังเกตการณ์คนอื่น (เช่น valueChanges) สำหรับ HTTP observables HTTP แบบสแตนด์อโลนคุณสามารถยกเลิกและสมัครสมาชิกใหม่ได้ด้วยตนเอง
Stevethemacguy

235

สัญญาทั้งสองและสิ่งที่สังเกตได้จะช่วยให้เราทำงานกับฟังก์ชันแบบอะซิงโครนัสใน JavaScript พวกเขาจะคล้ายกันมากในหลายกรณีอย่างไรก็ตามยังมีความแตกต่างบางอย่างระหว่างทั้งสองเช่นกันสัญญาเป็นค่าที่จะแก้ไขในasynchronousลักษณะเช่นการโทรhttp บนมืออื่น ๆ , observables จัดการกับลำดับของเหตุการณ์ที่ไม่ตรงกัน ความแตกต่างที่สำคัญระหว่างพวกเขาอยู่ด้านล่าง:

สัญญาว่า:

  • มีหนึ่งท่อ
  • โดยปกติจะใช้กับการส่งคืนข้อมูล async เท่านั้น
  • ไม่ใช่เรื่องง่ายที่จะยกเลิก

สังเกต:

  • ยกเลิกได้
  • สามารถปรับได้อีกครั้งโดยธรรมชาติเช่นลองใหม่และลองใหม่อีกครั้งเมื่อ
  • สตรีมข้อมูลในหลาย ๆ ท่อ
  • มีการดำเนินการเหมือนอาเรย์เช่นแผนที่ตัวกรองและอื่น ๆ
  • สามารถสร้างจากแหล่งอื่นเช่นเหตุการณ์
  • เป็นฟังก์ชั่นซึ่งสามารถสมัครรับข้อมูลได้ในภายหลัง

นอกจากนี้ฉันได้สร้างภาพกราฟิกสำหรับคุณด้านล่างเพื่อแสดงความแตกต่างด้วยสายตา:

ภาพสัญญาและที่สังเกตได้


4
สัญญาว่า "ไม่ใช่เรื่องง่ายที่จะยกเลิก" เป็นไปได้ไหมที่จะยกเลิก
Pardeep Jain

10
ใช่มีวิธีที่จะยกเลิกพวกเขาเช่นกัน ... บางคนใช้ห้องสมุด Bluebird หรือบุคคลที่สาม ... นอกจากนี้ยังใช้ห้องสมุด Q ใน Angular มีวิธีที่จะยกเลิก ... แต่อย่างที่ฉันบอกว่าไม่สะดวกมาก
Alireza

การมีท่อหนึ่งท่อบางครั้งก็มีข้อได้เปรียบเช่น ใน APP_INITIALIZER หากคุณมีหลายขั้นตอนจะไม่สามารถเสร็จสิ้นบางครั้งหรือเสร็จสิ้นหลายครั้ง
windmaomao

6
การยกเลิก a Promiseเป็นวิธีที่ผิดที่จะคิดเกี่ยวกับสัญญา Promiseความรับผิดชอบมันเท่านั้นที่จะประสบความสำเร็จในการจัดการหรือความล้มเหลวในทางที่เข้ากันได้ async .. ถ้าคุณต้องการที่จะยกเลิกการร้องขอ http คุณยกเลิกคำขอที่ไม่สัญญาและทำให้ผลของการยกเลิกทั้งตอบสนองหรือปฏิเสธสัญญา jsfiddle.net/greggman/ea0yhd4p
gman

2
@gman อย่างแน่นอน สัญญาก็แสดงให้เห็นถึงอนาคตบางอย่างคุ้มค่า มันไม่ได้เป็นตัวแทนของการดำเนินงานซึ่งจะสร้างมูลค่า คุณไม่สามารถยกเลิกค่าได้ คุณไม่สามารถลองอีกครั้งค่า มันเป็นเพียงคุณค่า มันอาจจะมีหรือไม่มีอยู่และมันอาจไม่เคยเกิดขึ้นเพราะมีข้อยกเว้นเกิดขึ้น แต่นั่นก็คือ
Yona Appletree

75

สัญญา

  1. คำจำกัดความ: ช่วยให้คุณเรียกใช้ฟังก์ชันแบบอะซิงโครนัสและใช้ค่าส่งคืน (หรือข้อยกเว้น) แต่เพียงครั้งเดียวเท่านั้นเมื่อดำเนินการ
  2. ไม่ขี้เกียจ
  3. ไม่สามารถยกเลิกได้ (มี Promise library ซึ่งนั่นรองรับการยกเลิก แต่ ES6 Promise อยู่ไม่ไกล) การตัดสินใจที่เป็นไปได้สองอย่างคือ
    • ปฏิเสธ
    • แก้ไข
  4. ไม่สามารถลองใหม่ได้ (สัญญาควรเข้าถึงฟังก์ชั่นดั้งเดิมที่ส่งคืนสัญญาเพื่อให้มีความสามารถในการลองซ้ำซึ่งเป็นวิธีปฏิบัติที่ไม่ดี)

observables

  1. คำจำกัดความ: ช่วยให้คุณเรียกใช้ฟังก์ชันแบบอะซิงโครนัสและใช้ค่าส่งคืนในลำดับต่อเนื่อง ( หลายครั้ง ) เมื่อดำเนินการ
  2. โดยค่าเริ่มต้นมันเป็นขี้เกียจที่ปล่อยออกมาค่าเมื่อเวลาดำเนินการ
  3. มีโอเปอเรเตอร์จำนวนมากที่ช่วยลดความยุ่งยากในการเขียนโค้ด
  4. ผู้ประกอบการหนึ่งลองใหม่อีกครั้งสามารถนำมาใช้เพื่อลองอีกครั้งเมื่อใดก็ตามที่จำเป็นถ้าเราต้องลองส่งใหม่ที่สังเกตได้ขึ้นอยู่กับเงื่อนไขบางอย่างretryWhenสามารถนำมาใช้

    หมายเหตุ : รายชื่อผู้ประกอบการพร้อมกับไดอะแกรมแบบโต้ตอบมีให้ที่นี่ที่RxMarbles.com


67

มีข้อเสียอย่างหนึ่งของ Observables ที่ขาดหายไปในคำตอบ สัญญาอนุญาตให้ใช้ฟังก์ชัน async / await ของ ES7 คุณสามารถเขียนโค้ดแบบอะซิงโครนัสได้เพราะมันจะเป็นการเรียกฟังก์ชั่นซิงโครนัสดังนั้นคุณไม่จำเป็นต้องโทรกลับอีก ความเป็นไปได้เพียงอย่างเดียวสำหรับ Observables ในการทำเช่นนี้คือการแปลงเป็นสัญญา แต่เมื่อคุณแปลงเป็นสัญญาคุณสามารถมีค่าตอบแทนได้เพียงครั้งเดียว:

async function getData(){
    const data = await observable.first().toPromise();
    //do stuff with 'data' (no callback function needed)
}

อ่านเพิ่มเติม: ฉันจะ "รอ" ใน Rx Observable ได้อย่างไร


21
ยังแปลกใจว่าทำไมไม่มีใครชี้ว่านักฆ่าตัวยงของสัญญานี้ - ความเรียบง่ายและโปร่งใสขอบคุณ async / ที่รอ ฉันเปลี่ยนไปที่สัญญาเพียงเพื่อความสามารถในการเขียนรหัสแบน ตรรกะทางธุรกิจอย่างง่ายและรหัสการโต้ตอบกับ UI ไม่ควรมีลักษณะเหมือนวิทยาศาสตร์จรวดและมีมลภาวะจากขุมนรกของการขยายปฏิกิริยา นอกจากนี้ async / await ไม่เพียง แต่ในอนาคตคุณสามารถใช้งานได้ในแอพการผลิตสาธารณะโดยใช้ transpilers ฉันใช้ TypeScript 2.3 และมันยอดเยี่ยมเหมือนภาษาจริง
evilkos

ดี แต่คิดในทางที่ตอบโต้และทั้งหมดนี้มี RxOperators บางทีนี่อาจไม่ใช่คุณสมบัตินักฆ่า
JorgeTovar

37

สัญญาและ Observables ทั้งสองจัดการการโทรแบบอะซิงโครนัสเท่านั้น

นี่คือความแตกต่างระหว่างพวกเขา:

น่าติดตาม

  1. ปล่อยค่าหลายค่าในช่วงเวลาหนึ่ง
  2. จะไม่ถูกเรียกจนกว่าเราจะสมัครเป็นสมาชิกของ Observable
  3. สามารถยกเลิกได้โดยใช้วิธีการยกเลิกการสมัคร ()
  4. จัดทำแผนที่สำหรับแต่ละตัวกรองลดลองใหม่และลองอีกครั้งเมื่อผู้ประกอบการ

คำมั่นสัญญา

  1. ปล่อยเพียงครั้งเดียวค่า

  2. โทรหาบริการที่ไม่มี. then and .catch

  3. ไม่สามารถยกเลิกได้

  4. ไม่ได้ให้บริการตัวดำเนินการใด ๆ


2
คุณหมายถึงอะไรโดยสัญญาส่งเสียงเพียงค่าเดียวในขณะที่สังเกตได้ปล่อยหลาย
อาเบล

2
คำมั่นสัญญาไม่ส่งผลให้เกิดมูลค่าเลยสัญญาคือมูลค่าเมื่อเวลาผ่านไป multicasts สัญญาที่ให้ความสำคัญกับสมาชิกหลายคน - เมื่อคุณถือสัญญาที่คุณมีค่าอยู่แล้ว สิ่งที่สังเกตได้ก็เหมือนฟังก์ชั่นที่บอกรับการกระทำนั้น
Benjamin Gruenbaum

1
@BenjaminGruenbaum ยังฉันไม่ได้รับค่าเฉลี่ยของสมาชิกหลายคนคุณสามารถให้ลิงค์หรือตัวอย่าง ขอบคุณ
Deepak Patidar

2
observable1.subscribe (subscriber1), observable1.subscribe (subscriber2) - สิ่งนี้จะเรียกใช้ฟังก์ชันหลาย ๆ ครั้ง
Benjamin Gruenbaum

2
โปรดแก้ไขโพสต์ของคุณและแสดงข้อความจริงแทนภาพหน้าจอ ผู้อื่นไม่สามารถคัดลอกและวางจากรูปภาพของคุณและยังไม่สามารถช่วยคุณแก้ไขข้อผิดพลาดทางไวยากรณ์มากมาย ดูรายละเอียดที่นี่ ขอบคุณ.
ปาง

26

แม้ว่าคำตอบนี้จะสาย แต่ฉันได้สรุปความแตกต่างด้านล่าง

สังเกต:

  1. การสังเกตการณ์เป็นเพียงสิ่งfunctionที่ต้องทำan observerและคืนค่า function Observer: an object with next, error.
  2. ผู้สังเกตการณ์อนุญาตให้subscribe/unsubscribeสตรีมข้อมูลปล่อยค่าถัดไปไปยังผู้notifyสังเกตการณ์ผู้สังเกตการณ์errorsและแจ้งผู้สังเกตการณ์เกี่ยวกับstream completion
  3. ผู้สังเกตการณ์ให้function to handle next valueข้อผิดพลาดและจุดสิ้นสุดของสตรีม (กิจกรรม ui การตอบสนอง http ข้อมูลที่มีเว็บซ็อกเก็ต)
  4. ทำงานร่วมกับmultiple valuesเมื่อเวลาผ่านไป
  5. มันเป็นcancel-able/retry-ableและสนับสนุนผู้ประกอบการเช่นmap,filter,reduceฯลฯ
  6. การสร้าง Observable สามารถ - Observable.create()- return Observable ที่สามารถเรียกใช้เมธอด on - Observer Observable.from()- แปลง array หรือ iterable เป็น - Observable Observable.fromEvent()- แปลงเหตุการณ์เป็น Observable - Observable.fromPromise()- แปลง Promise เป็น Observable - Observable.range()- ส่งคืนลำดับของจำนวนเต็มในช่วงที่กำหนด

สัญญา :

  1. คำสัญญาหมายถึงภารกิจที่จะเสร็จสิ้นในอนาคต

  2. สัญญากลายเป็นresolved by a value;

  3. สัญญาได้รับการปฏิเสธโดยข้อยกเว้น;

  4. ไม่cancellableและมันจะกลับมาa single value

  5. คำสัญญาเปิดเผยฟังก์ชั่น (then)

    ผลตอบแทน -then ใหม่ promise;

    - อนุญาตให้attachmentมีการดำเนินการตาม state ;

    - handlersจะ guaranteedต้องดำเนินการในorder attached;


20

ฉันเพิ่งจะจัดการกับปัญหาที่สัญญาเป็นทางออกที่ดีที่สุดและฉันแบ่งปันให้กับทุกคนที่สะดุดในคำถามนี้ในกรณีที่มีประโยชน์ (นี่คือคำตอบที่ฉันต้องการก่อนหน้านี้):

ในโครงการ Angular2 ฉันมีบริการที่ใช้พารามิเตอร์บางอย่างและส่งกลับรายการค่าเพื่อเติมเมนูแบบหล่นลงบนแบบฟอร์ม เมื่อองค์ประกอบของแบบฟอร์มเริ่มต้นฉันต้องเรียกใช้บริการเดียวกันหลาย ๆ ครั้งด้วยพารามิเตอร์ที่แตกต่างกันเพื่อกำหนดจำนวนเมนูแบบเลื่อนลงที่แตกต่างกัน แต่ถ้าฉันเพียงแค่จัดคิวตัวแปรทั้งหมดเพื่อเรียกใช้บริการเพียงคนสุดท้ายที่ประสบความสำเร็จ ออก. บริการดึงข้อมูลจากฐานข้อมูลสามารถจัดการได้ครั้งละหนึ่งคำขอเท่านั้น

วิธีเดียวที่จะเติมตัวแปรเมนูแบบเลื่อนลงได้สำเร็จคือการเรียกใช้บริการในลักษณะที่ป้องกันไม่ให้มีการประมวลผลการร้องขอใหม่จนกว่าการร้องขอครั้งสุดท้ายจะเสร็จสิ้นและกลไกสัญญา /. แล้วแก้ปัญหาได้อย่างดี

  fetchValueList(listCode): Promise<any> {
      return this.dataSvc.getValueList(listCode, this.stateSvc.currentContext, this.stateSvc.currentLanguageCode)
          .map(response => response.json())
          .toPromise();
  }

  initializeDropDowns() {
      this.fetchValueList('First-Val-List')
          .then(data => {
              this.firstValList = data;
              return this.fetchValueList('Second-Val-List')
          }).then(data => {
              this.secondValList = data;
              return this.fetchValueList('Third-Val-List')
          }).then(data => {
              this.thirdValList = data;
          })  }

ฉันกำหนดฟังก์ชั่นในองค์ประกอบแล้วเรียก initializeDropDowns () ใน ngOnInit

ฟังก์ชัน fetchValueList ส่งคืน Promise ดังนั้นการเรียกครั้งแรกผ่าน listCode แรกและเมื่อ Promise แก้ไขค่าส่งคืนจะอยู่ในตัวแปรข้อมูลในบล็อก. if แล้วเราสามารถกำหนดให้ตัวแปร this.firstValList เนื่องจากฟังก์ชันส่งคืนข้อมูลเราทราบว่าบริการเสร็จสิ้นแล้วและปลอดภัยที่จะโทรอีกครั้งด้วย listCode ที่สองค่าที่ส่งคืนจะอยู่ในตัวแปรข้อมูลในบล็อก. next ถัดไปจากนั้นเรากำหนดให้ตัวแปร this.secondValList

เราสามารถเชื่อมโยงสิ่งนี้ได้หลายครั้งตามที่ต้องการเพื่อเติมตัวแปรทั้งหมดและในบล็อกรหัสสุดท้ายเราเพียงละเว้นข้อความสั่งคืนและบล็อกถูกยกเลิก

นี่เป็นกรณีการใช้งานที่เฉพาะเจาะจงซึ่งเรามีบริการเดียวที่จำเป็นต้องเรียกใช้หลายครั้งในขณะที่องค์ประกอบเริ่มต้นและที่บริการจะต้องทำการดึงข้อมูลและคืนค่าก่อนที่จะสามารถเรียกได้อีกครั้ง แต่ในกรณีนี้ วิธีการ Promise / .then นั้นสมบูรณ์แบบ


3
สิ่งนี้เป็นไปได้แน่นอนด้วยสิ่งที่สังเกตได้ ตัวอย่างเช่นคุณสามารถใช้scan()เพื่อสร้างกระแสข้อมูลที่สังเกตได้ตามลำดับ อย่างไรก็ตามวิธีการของคุณอาจชัดเจนและเข้าใจง่ายขึ้น
lex82

1
คุณสามารถแทนที่ "แล้ว" ด้วย "switchMap" และทำสิ่งเดียวกันกับ w / observables
ดร. ซี. Hilarius

1
ปัญหาเกี่ยวกับ switchMap ที่ฉันเข้าใจคือมันจะเริ่มต้นคำขอทั้งหมดในแบบขนานและรอจนกว่าพวกเขาจะกลับมาทั้งหมดแล้วส่งกลับค่าไปยังฟังก์ชั่นการโทรในขณะที่ฉันอยู่ในสถานการณ์ของฉันฉันมีเซิร์ฟเวอร์เดียวที่ฉันไม่สามารถ โทรหลายครั้งในแบบคู่ขนาน (เนื่องจากเซิร์ฟเวอร์จะส่งคำขอที่ยังไม่เสร็จเมื่อมีคนเข้ามาใหม่) ดังนั้นฉันต้องตรวจสอบให้แน่ใจว่าการโทรแต่ละครั้งไปยังบริการฐานข้อมูลเสร็จสมบูรณ์ก่อนเริ่มการโทรใหม่และสัญญา / ดูเหมือนว่าจะดีที่สุด อาจเป็นวิธีเดียวที่จะแก้ปัญหานั้น
สตีเฟ่นอาร์สมิ ธ

1
ทำไมคุณไม่ใช้ mergeMap ที่มีสายโซ่ เท่าที่ฉันเข้าใจรหัสของคุณอันนี้ค่อนข้างง่ายและทำงานได้ดีตามตัวอย่างของคุณ @ StephenR.Smith
Ore

1
@Ore คุณสามารถเพิ่มตัวอย่างรหัสของการแก้ปัญหาเดียวกันกับคำตอบอื่นได้หรือไม่? จะเป็นการอ้างอิงที่ดีและอาจเป็นโอกาสในการปรับโครงสร้างที่ดีในอนาคต ข้อกำหนดคือรหัสใดก็ตามที่ไม่สามารถเรียกใช้บริการแบ็คเอนด์ในแบบคู่ขนานได้ก็ต้องโทรรอรับค่าส่งคืนและโทรอีกครั้ง
Stephen R. Smith

20

ฉันเชื่อว่าคำตอบอื่น ๆ ทั้งหมดควรกำจัดข้อสงสัยของคุณ อย่างไรก็ตามฉันแค่อยากจะเพิ่มสิ่งที่สังเกตได้นั้นขึ้นอยู่กับการเขียนโปรแกรมการใช้งานและฉันพบว่ามีประโยชน์มากกับฟังก์ชั่นที่มาพร้อมกับมันเช่น map, flatmap, ลด, zip ความสอดคล้องของเว็บที่ประสบความสำเร็จโดยเฉพาะอย่างยิ่งเมื่อมันขึ้นอยู่กับคำขอ API คือการปรับปรุงที่โหดร้าย

ฉันแนะนำอย่างยิ่งเอกสารนี้เนื่องจากเป็นเอกสารอย่างเป็นทางการของ reactiveX และฉันพบว่าเอกสารนั้นชัดเจนที่สุด

หากคุณต้องการเข้าร่วม observables ฉันจะแนะนำโพสต์ 3 ส่วนนี้: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/

แม้ว่ามันจะมีความหมายสำหรับ RxJava แนวคิดนั้นเหมือนกันและได้รับการอธิบายอย่างดี ในเอกสาร reactiveX คุณมีสิ่งที่เทียบเท่าสำหรับแต่ละฟังก์ชัน คุณต้องมองหา RxJS


18

Promise:

  • ให้คุณค่าในอนาคตเดียว
  • ไม่ขี้เกียจ;
  • ไม่สามารถยกเลิกได้

สังเกต:

  • ปล่อยค่าหลายค่าในช่วงเวลา;
  • ขี้เกียจ;
  • ที่บอกเลิก;
  • รองรับแผนที่กรองลดและผู้ประกอบการที่คล้ายกัน

คุณสามารถใช้สัญญาแทนที่จะเป็นสิ่งที่สังเกตได้เมื่อเรียก HTTP ในเชิงมุมหากคุณต้องการ


16

ข้อมูลทั่วไป:

  • ทั้งสัญญาและสิ่งที่สังเกตได้ช่วยให้เราจัดการกับการดำเนินการแบบอะซิงโครนัส พวกเขาสามารถเรียกกลับบางอย่างเมื่อการดำเนินการแบบอะซิงโครนัสเหล่านี้เสร็จสิ้น
  • สัญญาสามารถจัดการเหตุการณ์เดียวเท่านั้นสิ่งที่สังเกตได้มีไว้สำหรับสตรีมของเหตุการณ์เมื่อเวลาผ่านไป
  • ไม่สามารถยกเลิกสัญญาได้เมื่อรอดำเนินการ
  • Data Observables สามารถปล่อยออกมาได้โดยใช้โอเปอเรเตอร์

คุณสามารถใช้สิ่งที่สังเกตได้สำหรับจัดการกับพฤติกรรมแบบอะซิงโครนัสเสมอเนื่องจากสิ่งที่สังเกตได้มีฟังก์ชันการทำงานทั้งหมดที่สัญญาให้ไว้ (+ พิเศษ) อย่างไรก็ตามบางครั้งฟังก์ชันการทำงานพิเศษนี้ที่ข้อเสนอสังเกตไม่จำเป็น จากนั้นจะเป็นค่าใช้จ่ายเพิ่มเติมในการนำเข้าไลบรารีเพื่อใช้งาน

เมื่อใดที่จะใช้สัญญา:

ใช้สัญญาเมื่อคุณมีการ ดำเนินการ async เดียวซึ่งคุณต้องการประมวลผลผลลัพธ์ ตัวอย่างเช่น:

var promise = new Promise((resolve, reject) => {
  // do something once, possibly async
  // code inside the Promise constructor callback is getting executed synchronously

  if (/* everything turned out fine */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});

//after the promise is resolved or rejected we can call .then or .catch method on it

promise.then((val) => console.log(val))      // logs the resolve argument
       .catch((val) => console.log(val));    // logs the reject argument

ดังนั้นคำสัญญารันรหัสบางอย่างที่มันสามารถแก้ไขหรือปฏิเสธ หากการแก้ปัญหาอย่างใดอย่างหนึ่งหรือปฏิเสธที่เรียกว่าสัญญาไปจากสถานะรอดำเนินการอย่างใดอย่างหนึ่งได้รับการแก้ไขหรือปฏิเสธรัฐ เมื่อสถานะสัญญาได้รับการแก้ไขthen()วิธีการที่เรียกว่า เมื่อสถานะสัญญาถูกปฏิเสธcatch()วิธีการจะถูกเรียก

เมื่อใดที่จะใช้ Observables:

ใช้สิ่งที่สังเกตได้เมื่อมีกระแสข้อมูล (ของข้อมูล) ในช่วงเวลาที่คุณต้องได้รับการจัดการ กระแสเป็นลำดับขององค์ประกอบข้อมูลที่มีการเปิดให้บริการในช่วงเวลา ตัวอย่างของสตรีมคือ:

  1. กิจกรรมของผู้ใช้เช่นคลิกหรือเหตุการณ์ที่สำคัญ ผู้ใช้สร้างกิจกรรม (ข้อมูล) เมื่อเวลาผ่านไป
  2. Websockets หลังจากไคลเอนต์ทำการเชื่อมต่อ WebSocket กับเซิร์ฟเวอร์มันดันข้อมูลเมื่อเวลาผ่านไป

ในการสังเกตตัวเองจะถูกระบุไว้เมื่อเหตุการณ์ต่อไปเกิดขึ้นเมื่อมีข้อผิดพลาดเกิดขึ้นหรือเมื่อสังเกตจะเสร็จสมบูรณ์ จากนั้นเราสามารถสมัครรับข้อมูลนี้ซึ่งเปิดใช้งานได้และในการสมัครสมาชิกนี้เราสามารถส่งกลับได้ 3 ครั้ง (ไม่จำเป็นต้องผ่านทุกครั้ง) หนึ่งการเรียกกลับที่จะดำเนินการเพื่อความสำเร็จหนึ่งข้อผิดพลาดในการติดต่อกลับและอีกหนึ่งการติดต่อกลับเพื่อความสำเร็จ ตัวอย่างเช่น:

const observable = Rx.Observable.create(observer => {
  // create a single value and complete
  observer.onNext(1);
  observer.onCompleted();
});

source.subscribe(
  x => console.log('onNext: %s', x),   //  success callback
  e => console.log('onError: %s', e),  //  error callback
  () => console.log('onCompleted')     //  completion callback
 );

// first we log: onNext: 1
//  then we log: onCompleted

เมื่อสร้างสิ่งที่สังเกตได้มันต้องใช้ฟังก์ชันการโทรกลับซึ่งให้ผู้สังเกตการณ์เป็นอาร์กิวเมนต์ เมื่อวันที่สังเกตการณ์นี้แล้วคุณสามารถโทรonNext, ,onCompleted onErrorจากนั้นเมื่อ Observable สมัครเป็นสมาชิกมันจะโทรกลับที่สอดคล้องกันที่ส่งผ่านไปยังการสมัครสมาชิก


9

สัญญา - ระบุมูลค่าในอนาคตเดียว ไม่ขี้เกียจ ไม่สามารถยกเลิกได้ มันจะปฏิเสธหรือแก้ไข

สังเกตได้ - ระบุมูลค่าในอนาคตหลายรายการ ขี้เกียจ . ยกเลิกได้ มันมีวิธีการอื่น ๆ แผนที่สดกรองลด


8

สัญญากับความคล้ายคลึงกันที่สังเกตได้ก่อน

  1. ทั้งสองใช้เพื่อจัดการรหัส async
  2. โปรดดูตัวอย่างสัญญา ตัวสร้างสัญญาจะส่งผ่านฟังก์ชันการแก้ปัญหาการอ้างอิงซึ่งจะถูกเรียกเมื่อมันถูกเรียกด้วยค่าบางอย่างเมื่อทำภารกิจ async เสร็จสมบูรณ์

const promise = new Promise(resolve => {
  setTimeout(() => {
    resolve("Hello from a Promise!");
  }, 2000);
});

promise.then(value => console.log(value));

  1. ตัวอย่างที่สังเกตได้ในขณะนี้ ที่นี่เราผ่านฟังก์ชั่นเพื่อให้สังเกตได้ผู้สังเกตการณ์ในการจัดการงาน async แตกต่างจากการแก้ไขในสัญญามันมีวิธีการดังต่อไปนี้และสมัครสมาชิกแทน

  2. ดังนั้นทั้งสองจัดการงาน async ตอนนี้เรามาดูความแตกต่าง


const observable = new Observable(observer => {
  setTimeout(() => {
    observer.next('Hello from a Observable!');
  }, 2000);
});

observable.subscribe(value => console.log(value));

สัญญากับความแตกต่างที่สังเกตได้

คำมั่นสัญญา

  1. มันแก้ไขหรือปฏิเสธค่าเดียวและสามารถจัดการงาน async ค่าเดียวในเวลา
  2. สัญญาเมื่อแก้ไขค่า async แล้วเสร็จจะไม่สามารถใช้ได้อีกต่อไปเพียงแค่ใช้ครั้งเดียวและที่นี่จะสั้น
  3. ไม่สามารถยกเลิกได้
  4. ไม่รองรับ rxjs สำหรับผู้ประกอบการ

น่าติดตาม

  1. ความสามารถในการเปล่งค่าแบบอะซิงโครนัสหลายค่า
  2. ใช้เพื่อจัดการกระแสของเหตุการณ์หรือค่า พิจารณาว่าคุณมีงานหรือค่ามากมายหลายแบบและคุณต้องการให้ทุกครั้งที่มีการแทรกค่าเข้าไปสิ่งนี้ควรจัดการโดยอัตโนมัติ เมื่อใดก็ตามที่คุณส่งค่าลงในอาร์เรย์นี้สมาชิกทั้งหมดจะได้รับค่าล่าสุดโดยอัตโนมัติ
  3. สิ่งที่สังเกตได้มีประโยชน์สำหรับการสังเกตการเปลี่ยนแปลงของอินพุต, ช่วงเวลาซ้ำ, ค่าการออกอากาศไปยังองค์ประกอบลูกทั้งหมด, การแจ้งเตือนแบบพุชเว็บซ็อกเก็ต ฯลฯ
  4. สามารถยกเลิกได้โดยใช้วิธีการยกเลิกการสมัครได้ตลอดเวลา
  5. อีกส่วนที่ดีสุดท้ายที่สัญญาว่าได้รับการสนับสนุนสำหรับผู้ประกอบการ rxjs คุณมีผู้ให้บริการไพพ์หลายรายส่วนใหญ่ทำแผนที่ตัวกรองสวิตช์แผนที่รวมล่าสุด ฯลฯ เพื่อแปลงข้อมูลที่สังเกตได้ก่อนสมัคร

ป้อนคำอธิบายรูปภาพที่นี่



6

ทั้งสัญญาและสิ่งที่สังเกตได้ช่วยให้เราจัดการกับการดำเนินการแบบอะซิงโครนัส พวกเขาสามารถเรียกกลับบางอย่างเมื่อการดำเนินการแบบอะซิงโครนัสเหล่านี้เสร็จสิ้น

Angular ใช้ Observables ซึ่งมาจาก RxJS แทนที่จะสัญญาว่าจะจัดการกับ HTTP

Below are some important differences in promises & Observables.

ความแตกต่างระหว่างสัญญาและสิ่งที่สังเกตได้


1
ข้อมูลที่มีการจัดตารางดูเหมือนไม่ถูกต้องชื่อควรถูกเปลี่ยน
Derrick.X

1
โปรดแก้ไขโพสต์ของคุณและแสดงเนื้อหาจริงเป็นข้อความแทนที่จะเป็นภาพหน้าจอ คนอื่นไม่สามารถคัดลอกและวางจากรูปภาพของคุณ ดูรายละเอียดที่นี่ ขอบคุณ.
ปาง

6

คำสัญญาส่งเสียงเหตุการณ์เดียวเมื่อกิจกรรม async เสร็จสิ้นหรือล้มเหลว

การสังเกตการณ์นั้นเหมือนกระแส (ในหลายภาษา) และอนุญาตให้ส่งผ่านเหตุการณ์อย่างน้อยศูนย์หรือมากกว่านั้นซึ่งจำเป็นต้องมีการติดต่อกลับสำหรับทุกเหตุการณ์

การสังเกตบ่อยครั้งเป็นสิ่งที่ต้องการมากกว่าคำสัญญาเนื่องจากเป็นไฮไลท์ของสัญญาและอีกมากมาย ด้วย Observable ไม่สำคัญว่าคุณจะต้องจัดการกับเหตุการณ์ 0, 1 หรือเหตุการณ์ต่าง ๆ คุณสามารถใช้ API ที่คล้ายกันสำหรับแต่ละกรณี

สัญญา: สัญญาส่งเสียงค่าเดียว

ตัวอย่างเช่น:

const numberPromise = new Promise((resolve) => {
    resolve(5);
    resolve(10);
});

numberPromise.then(value => console.log(value));
// still prints only 5

สังเกต: ปล่อยค่าหลายค่าในช่วงเวลาหนึ่ง

ตัวอย่างเช่น:

  const numberObservable = new Observable((observer) => {
        observer.next(5);
        observer.next(10);
    });

numberObservable.subscribe(value => console.log(value));
// prints 5 and 10

เราสามารถนึกถึงสิ่งที่สังเกตได้เหมือนสตรีมที่ปล่อยค่าหลายค่าในช่วงเวลาหนึ่งและฟังก์ชันการเรียกกลับที่เหมือนกันถูกเรียกใช้สำหรับแต่ละรายการที่ปล่อยออกมาเพื่อให้สามารถสังเกตได้ว่าเราสามารถใช้ API เดียวกันเพื่อจัดการข้อมูลแบบอะซิงโครนัส ไม่ว่าข้อมูลนั้นจะถูกส่งเป็นค่าเดียวหรือหลายค่าในช่วงระยะเวลาหนึ่ง

Promise:

  • สัญญาไม่ได้ขี้เกียจ
  • ไม่สามารถยกเลิกสัญญาได้

สังเกต:

  • สังเกตได้คือ Lazy "สังเกตได้" ช้า จะไม่ถูกเรียกจนกว่าเราจะสมัครเป็นสมาชิก
  • สามารถยกเลิกการสังเกตได้โดยใช้วิธีการยกเลิกการสมัคร ()
  • นอกจากนี้ Observable ยังมอบโอเปอเรเตอร์ที่ทรงพลังมากมายเช่นแผนที่, foreach, filter, ลด, ลองใหม่, ลองใหม่อีกครั้งเมื่อเป็นต้น

สัญญาเชิงมุมเทียบกับสิ่งที่สังเกตได้


5

สัญญาส่งเสียงค่าเดียวในขณะที่สังเกตได้ปล่อยหลายค่า ดังนั้นในขณะที่จัดการคำขอ HTTP สัญญาสามารถจัดการคำตอบเดียวสำหรับคำขอเดียวกัน แต่จะเกิดอะไรขึ้นถ้ามีการตอบกลับคำขอเดียวกันหลายครั้งเราต้องใช้ Observable ใช่สังเกตได้สามารถจัดการการตอบสนองหลายอย่างสำหรับคำขอเดียวกัน

คำมั่นสัญญา

const promise = new Promise((data) =>
{ data(1);
  data(2);
  data(3); })
.then(element => console.log(‘Promise ‘ + element));

เอาท์พุต

Promise 1

น่าติดตาม

const observable = new Observable((data) => {
data.next(1);
data.next(2);
data.next(3);
}).subscribe(element => console.log('Observable ' + element));

เอาท์พุต

Observable 1
Observable 2
Observable 3

3

ด้านล่างนี้เป็นข้อแตกต่างที่สำคัญในสัญญาและสิ่งที่สังเกตได้

คำมั่นสัญญา

  • ปล่อยค่าเดียวเท่านั้น
  • ไม่สามารถยกเลิกได้
  • ไม่สามารถแบ่งปันได้
  • อะซิงโครนัสเสมอ

น่าติดตาม

  • ปล่อยหลายค่า
  • ดำเนินการเฉพาะเมื่อมีการเรียกหรือมีผู้สมัครเป็นสมาชิก
  • สามารถยกเลิกได้
  • สามารถแบ่งปันและสมัครสมาชิกนั้นมูลค่าที่ใช้ร่วมกันโดยสมาชิกหลายคน และสมาชิกทั้งหมดจะดำเนินการในเวลาเดียว
  • อาจไม่ตรงกัน

เพื่อความเข้าใจที่ดีขึ้นโปรดอ้างถึงhttps://stackblitz.com/edit/observable-vs-promises


3

ฉันเห็นผู้คนจำนวนมากที่ใช้อาร์กิวเมนต์ที่ Observable เห็นว่าเป็น "ยกเลิกได้" แต่มันค่อนข้างง่ายที่จะทำให้สัญญา "ยกเลิกได้"

function cancellablePromise(body) {
  let resolve, reject;
  const promise = new Promise((res, rej) => {
    resolve = res; reject = rej;
    body(resolve, reject)
  })
  promise.resolve = resolve;
  promise.reject = reject;
  return promise
}

// Example 1: Reject a promise prematurely
const p1 = cancellablePromise((resolve, reject) => {
  setTimeout(() => resolve('10', 100))
})

p1.then(value => alert(value)).catch(err => console.error(err))
p1.reject(new Error('denied')) // expect an error in the console

// Example: Resolve a promise prematurely
const p2 = cancellablePromise((resolve, reject) => {
  setTimeout(() => resolve('blop'), 100)
})

p2.then(value => alert(value)).catch(err => console.error(err))
p2.resolve(200) // expect an alert with 200


2

คำตอบสั้น ๆ :

เห็นได้ชัดคือดีกว่ามันมีคุณสมบัติสัญญาทั้งหมดรวมถึงคุณสมบัติพิเศษ


คำตอบยาว:

สัญญา:

  • ใช้ครั้งเดียว "ส่งคืนข้อมูลครั้งเดียว"
  • ไม่มีการยกเลิก
  • ผู้ฟังหนึ่งคน
  • ไม่มีการรองรับซ็อกเก็ตหนึ่งฟัง

สังเกต:

  • ส่งคืนข้อมูลหลายครั้งเมื่อมีการเปลี่ยนแปลงข้อมูล
  • ยกเลิกการสนับสนุน
  • รองรับซ็อกเก็ต
  • สนับสนุนผู้ฟังจำนวนมากและแจ้งเตือนเมื่อมีการเปลี่ยนแปลงข้อมูล
  • สนับสนุนแผนที่ตัวกรองลด

ฉันไม่คิดว่าคุณสามารถพูดได้ว่าสิ่งที่สังเกตได้ดีกว่า มีจำนวนข้อเสียสำหรับ Observables ที่ระบุไว้ในคำตอบต่าง ๆ ที่นี่ สิ่งที่โดดเด่นสำหรับฉันคือความซับซ้อนของการสังเกตการณ์และพวกมันไม่สามารถทำงานได้โดยตรงกับการรอคอย / การซิงค์ ฉันพบว่าพวกเขายากที่จะทำงานด้วยเพราะคุณไม่สามารถระบุพฤติกรรมของ Observable เมื่อใช้มัน - คุณต้องดูรหัสที่สร้างมันขึ้นมา ในขณะที่สัญญาคุณรู้ว่าพวกเขาทำงานอย่างไรเสมอ ตัวอย่างเช่นบางครั้งการสมัครสมาชิก Observable มีผลข้างเคียง (เช่นคำขอ http) แต่บางครั้งก็ไม่
Yona Appletree

สำหรับเชิงมุมมันขึ้นอยู่กับกรณีของคุณ สำหรับกรณีส่วนใหญ่เราจะทำงานกับบริการและข้อมูลบางอย่างซึ่งจะส่งผลกระทบต่อสถานที่ต่าง ๆ ซ็อกเก็ตการยกเลิกแผนที่ตัวกรองและการลด ดังนั้นจะดีกว่าในกรณีเหล่านั้นตามที่สัญญาไม่สนับสนุนพวกเขา ดังนั้นอีกครั้งมันขึ้นอยู่กับกรณีของคุณ
Amr Ibrahim

2

ในขณะที่คำตอบที่ยอมรับนั้นดีโดยทั่วไปฉันไม่คิดว่ามันจะเน้นว่าเมื่อต้องรับมือกับ Angular Components คุณมักจะต้องการใช้ Observable เพราะสนับสนุนการยกเลิก คำสัญญาไม่สามารถยกเลิกได้และจะแก้ไขได้แม้ว่าองค์ประกอบของคุณจะถูกทำลาย เชิงมุมมีแนวโน้มที่จะให้อภัยจนกว่าจะไม่

ตัวอย่างเช่นการตรวจจับการเปลี่ยนแปลงด้วยตนเองในองค์ประกอบที่ทำลายจะทำให้เกิดข้อยกเว้น:

ngOnInit() {
  // promise api
  this.service.getData().then(d => {
     this.data = d;
     this.changeDetectorRef.detectChanges();
  });

  // observable api
  this.service.getData().pipe(takeUntil(this.unsubscribe)).subscribe((d) => {
     this.data = d;
     this.changeDetectorRef.detectChanges();
  });
}

หากองค์ประกอบของคุณถูกทำลายก่อนที่สัญญาจะได้รับการแก้ไขคุณจะได้รับ attempt to use destroyed viewข้อผิดพลาดเมื่อสัญญาได้รับการแก้ไข

หรือถ้าคุณใช้สิ่งที่สังเกตได้ด้วยtakeUntilรูปแบบทันทีที่องค์ประกอบของคุณถูกทำลายการสมัครจะถูกยกเลิก

นี่เป็นตัวอย่างของการวางแผน แต่การรันโค้ดสำหรับส่วนประกอบที่ถูกทำลายอาจจะนำไปสู่ข้อบกพร่อง นอกจากว่าคุณต้องการทำเช่นนั้นด้วยเหตุผลบางอย่าง: p


2

บางสิ่งบางอย่างที่ฉันพบเจอในการอ่านบทช่วยสอนครั้งแรกและเอกสารนั้นเป็นแนวคิดของการทำมัลติคาสต์

ตรวจสอบให้แน่ใจว่าคุณทราบว่าโดยค่าเริ่มต้นการสมัครรับข้อมูลหลายรายการจะทริกเกอร์การประหารหลายครั้งใน Observable การสมัครสมาชิกหลายรายการในการโทร HTTP ครั้งเดียว Observable จะเรียกการโทร HTTP ที่เหมือนกันหลายรายการยกเว้นคุณ.share() (เปิดใช้งานการรับหลายผู้รับ)

คำสัญญาบังคับให้คุณจัดการกับสิ่งหนึ่งครั้งแกะข้อมูลจัดการข้อยกเว้นมีการสนับสนุนภาษาสำหรับสิ่งดีๆเช่น async / รอและเป็นเปลือยเปล่า

ผู้สังเกตการณ์มีระฆังและนกหวีดมากมาย แต่คุณต้องเข้าใจพลังที่คุณกำลังใช้งานหรืออาจถูกนำไปใช้ในทางที่ผิด


2

Promise:

Anync Event Handler - วัตถุสัญญาแสดงถึงความสำเร็จในที่สุด (หรือความล้มเหลว) ของการดำเนินการแบบอะซิงโครนัสและค่าผลลัพธ์

ไวยากรณ์:สัญญาใหม่ (ผู้บริหาร);

เช่น:

var promise_eg = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 300);
});

promise_eg.then(function(value) {
  console.log(value);
  // expected output: "foo"
});

console.log(promise_eg);

ป้อนคำอธิบายรูปภาพที่นี่

เกี่ยวกับสัญญา: มันมีหนึ่งขั้นตอนดังนั้นมันจะคืนค่าเพียงครั้งเดียวเมื่อมันถูกเรียก ตัวจัดการแบบทางเดียวดังนั้นเมื่อเรียกว่าคุณอาจไม่สามารถยกเลิกได้ ไวยากรณ์ที่มีประโยชน์ที่คุณสามารถเล่นได้เมื่อ ()และจากนั้น ()

observables:

สิ่งที่สังเกตได้คือคอลเล็กชันที่ขี้เกียจของค่าหลายค่าเมื่อเวลาผ่านไป มันเป็นวิธีการที่ยอดเยี่ยมสำหรับการดำเนินการแบบอะซิงก์ มันสามารถทำได้กับrxjsซึ่งมีการสนับสนุนข้ามแพลตฟอร์มสามารถใช้กับเชิงมุม / ปฏิกิริยา ฯลฯ

มันทำหน้าที่เหมือนซับในสตรีม สามารถหลายท่อ ดังนั้นเมื่อกำหนดแล้วคุณสามารถสมัครสมาชิกเพื่อรับผลตอบแทนในหลาย ๆ ที่

ไวยากรณ์: import * as Rx from "@reactivex/rxjs"; ถึง init:

Rx.Observable.fromEvent(button, "click"),
Rx.Subject()

ฯลฯ

เพื่อติดตาม: RxLogger.getInstance();

เช่น:

import { range } from 'rxjs';
import { map, filter } from 'rxjs/operators';

range(1, 200).pipe(
  filter(x => x % 2 === 1),
  map(x => x + x)
).subscribe(x => console.log(x));

เนื่องจากมันรองรับหลายขั้นตอนคุณสามารถติดตามผลได้ในหลายตำแหน่ง ป้อนคำอธิบายรูปภาพที่นี่ จึงมีความเป็นไปได้มากกว่าสัญญา

การใช้งาน: มันมีความเป็นไปได้มากกว่าเช่นmap, filter, pipe, map, concatMap etc


2

ความแตกต่างพื้นฐานระหว่างที่สังเกตได้และสัญญาคือ:

ป้อนคำอธิบายรูปภาพที่นี่


2
โปรดแก้ไขโพสต์ของคุณและแสดงเนื้อหาจริงเป็นข้อความแทนที่จะเป็นภาพหน้าจอ คนอื่นไม่สามารถคัดลอกและวางจากรูปภาพของคุณ ดูรายละเอียดที่นี่ ขอบคุณ.
ปาง

1

ของที่ระลึกมักจะถูกเปรียบเทียบกับสัญญา นี่คือความแตกต่างที่สำคัญ:

สิ่งที่สังเกตได้คือสิ่งที่ประกาศ; การคำนวณไม่เริ่มจนกว่าการสมัครสมาชิก สัญญาดำเนินการทันทีในการสร้าง สิ่งนี้ทำให้สิ่งที่สังเกตได้มีประโยชน์สำหรับการกำหนดสูตรอาหารที่สามารถเรียกใช้เมื่อใดก็ตามที่คุณต้องการผลลัพธ์

สิ่งที่สังเกตได้มีค่ามากมาย สัญญาให้หนึ่ง สิ่งนี้ทำให้สิ่งที่สังเกตได้มีประโยชน์ในการรับหลายค่าเมื่อเวลาผ่านไป

สังเกตได้แตกต่างระหว่างการผูกมัดและการสมัครสมาชิก สัญญามีเพียง. แล้ว () ส่วน สิ่งนี้ทำให้สิ่งที่สังเกตได้มีประโยชน์สำหรับการสร้างสูตรการแปลงที่ซับซ้อนที่ส่วนอื่น ๆ ของระบบใช้โดยไม่ทำให้งานต้องถูกดำเนินการ

Observables Subscription () รับผิดชอบการจัดการข้อผิดพลาด สัญญาผลักดันข้อผิดพลาดให้เด็กสัญญา สิ่งนี้ทำให้สิ่งที่สังเกตได้มีประโยชน์สำหรับการจัดการข้อผิดพลาดจากส่วนกลางและคาดการณ์ได้

นั่นคือความแตกต่างที่ง่ายที่สุดที่คุณอาจพบในเอกสาร ANGULAR.IO คำตอบที่เหลือจะได้รับโดยส่วนใหญ่ถูกต้องในสถานที่ของตัวเอง


1
  1. สัญญาจะเน้นเฉพาะค่าเดียวหรือการแก้ไขที่สามารถสังเกตได้คือกระแสข้อมูล

  2. สามารถยกเลิกของที่ระลึกได้ แต่สัญญานั้นไม่สามารถยกเลิกได้

คนที่รู้จักน้อยที่สุดอย่างน้อยก็สำหรับฉันคือ

  1. คำสัญญามีลักษณะของแบบอะซิงโครนัสเสมอ แต่สิ่งที่สังเกตได้สามารถเป็นได้ทั้งแบบซิงโครนัสและแบบอะซิงโครนัส

0
  1. สัญญามีความกระตือรือร้นในขณะที่สังเกตได้ขี้เกียจ
  2. คำสัญญาเป็นแบบอะซิงโครนัสเสมอในขณะที่การสังเกตสามารถเป็นแบบซิงโครนัสหรือแบบอะซิงโครนัส
  3. สัญญาสามารถให้ค่าเดียวในขณะที่สังเกตคือ
    กระแสของค่า (จาก 0 ถึงหลายค่า)
  4. คุณสามารถใช้ตัวดำเนินการ RxJS กับ Observable เพื่อรับสตรีมที่ปรับแต่งใหม่

-1

Observables and Promises ช่วยให้เราทำงานกับฟังก์ชันแบบอะซิงโครนัสใน JavaScript / typescript พวกเขามีความคล้ายคลึงกันมากในหลายกรณีอย่างไรก็ตามยังมีความแตกต่างระหว่างพวกเขา

ป้อนคำอธิบายรูปภาพที่นี่


1
โปรดแก้ไขโพสต์ของคุณและแสดงข้อความจริงแทนภาพหน้าจอ คนอื่นไม่สามารถคัดลอกและวางจากรูปภาพของคุณ ดูรายละเอียดที่นี่ ขอบคุณ.
ปาง

ยกเว้นว่าไม่ใช่รหัส แต่เป็นข้อมูลธรรมดาดังนั้นฉันคิดว่ามันโอเคที่จะโพสต์เป็นรูปภาพ
Alator

1
หยุดการคัดลอกวางจากวิดีโอ youtube ของ Kudvenkat ลงคะแนนจากฉัน! :)
Pratik

-2

มีคำตอบมากมายในหัวข้อนี้อยู่แล้วดังนั้นฉันจะไม่เพิ่มคำตอบที่ซ้ำซ้อน

แต่สำหรับคนที่เพิ่งเริ่มเรียนรู้จากการสังเกตการณ์ / เชิงมุมและสิ่งมหัศจรรย์ที่จะใช้เปรียบเทียบกับสัญญาฉันขอแนะนำให้คุณเก็บทุกอย่างที่สังเกตได้และแปลงสัญญาที่มีอยู่ทั้งหมดในโครงการของคุณเป็นที่สังเกตได้

เพียงเพราะกรอบเชิงมุมเองและชุมชนก็ล้วนใช้ Observable ดังนั้นจะเป็นประโยชน์เมื่อคุณรวมบริการเฟรมเวิร์กหรือโมดูลของบุคคลที่สามและเชื่อมโยงทุกอย่างเข้าด้วยกัน


ในขณะที่ฉันขอบคุณ downvotes ทั้งหมด แต่ฉันก็ยังคงยืนยันความคิดเห็นของฉันข้างต้นยกเว้นบางคนแสดงความคิดเห็นที่เหมาะสมเพื่อแสดงรายการบางสถานการณ์ที่อาจยังคงมีประโยชน์ในโครงการ Angular ของคุณเพื่อใช้สัญญามากกว่า Observables

แน่นอนว่าไม่มีความคิดเห็นใดที่ถูกต้อง 100% ในทุกกรณี แต่อย่างน้อยฉันก็คิดว่า 98% ของเวลาสำหรับโครงการเชิงพาณิชย์ตามปกติที่ดำเนินการใน Angular Framework สังเกตได้เป็นวิธีที่เหมาะสม

แม้ว่าคุณจะไม่ชอบมันที่จุดเริ่มต้นของโปรเจ็กต์งานอดิเรกง่ายๆของคุณคุณก็จะรู้ว่าส่วนประกอบเกือบทั้งหมดที่คุณโต้ตอบด้วยใน Angular และเฟรมเวิร์กของบุคคลที่สามที่เป็นมิตรกับ Angular ส่วนใหญ่กำลังใช้ Observables แล้ว จบลงด้วยการเปลี่ยนสัญญาของคุณเป็น Observable เพื่อสื่อสารกับพวกเขา

ส่วนประกอบเหล่านั้นรวมถึง แต่ไม่ จำกัด เพียง: HttpClient, ตัวสร้างแบบฟอร์ม, โมดูล / กล่องโต้ตอบวัสดุเชิงมุม, Ngrx store / effects และ ngx-bootstrap

ในความเป็นจริงสัญญาจากเชิงมุมระบบนิเวศฉันจัดการกับในอดีตที่ผ่านมา 2 APP_INITIALIZERปี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.