ความแตกต่างระหว่างPromise
และObservable
ในเชิงมุมคืออะไร?
ตัวอย่างในแต่ละกรณีจะเป็นประโยชน์ในการทำความเข้าใจทั้งสองกรณี ในสถานการณ์ใดที่เราสามารถใช้แต่ละกรณี
ความแตกต่างระหว่างPromise
และObservable
ในเชิงมุมคืออะไร?
ตัวอย่างในแต่ละกรณีจะเป็นประโยชน์ในการทำความเข้าใจทั้งสองกรณี ในสถานการณ์ใดที่เราสามารถใช้แต่ละกรณี
คำตอบ:
คำมั่นสัญญา
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()
... ที่มักจะมีประโยชน์มาก
Promise
พร้อมกับasync
/ await
ทำให้รหัสของคุณแบนอีกครั้ง! ในสถานการณ์ส่วนใหญ่และในโครงการที่ไม่เกี่ยวข้องกับวิทยาศาสตร์จรวดไม่จำเป็นต้องเขียนฟังก์ชันซ้อนที่น่ากลัวด้วยวิธีการที่ซับซ้อนโดยไม่จำเป็น คุณสามารถใช้async
/ await
วันนี้กับ transpilers เช่นTypeScript
และเขียนรหัสแบนที่มนุษย์อ่านได้จริงโดยไม่ต้องใช้แผ่นrxjs
สำเร็จรูปใด ๆ คุณอาจจะต้องใช้rxjs
บางครั้งในบางสถานการณ์เพราะมันมีหลายสิ่งหลายอย่างที่จะนำเสนอ
ทั้งสองPromises
และObservables
ให้ abstractions ที่ช่วยให้เราจัดการกับธรรมชาติแบบอะซิงโครนัสของแอปพลิเคชันของเรา ความแตกต่างระหว่างพวกเขาถูกชี้อย่างชัดเจนโดย@Günterและ @Relu
เนื่องจากข้อมูลโค้ดมีค่าหนึ่งพันคำให้อ่านตัวอย่างด้านล่างเพื่อทำความเข้าใจได้ง่ายขึ้น
ขอบคุณ @Christoph Burgdorf สำหรับบทความที่ยอดเยี่ยม
Angular ใช้ Rx.js Observables แทนที่จะให้สัญญากับการจัดการกับ HTTP
สมมติว่าคุณกำลังสร้างฟังก์ชั่นการค้นหาที่ควรแสดงผลลัพธ์ทันทีที่คุณพิมพ์ ฟังดูคุ้นเคย แต่มีความท้าทายมากมายที่มาพร้อมกับงานนั้น
HTTP
คำขอ โดยพื้นฐานแล้วเราต้องการตีเมื่อผู้ใช้หยุดพิมพ์แทนที่จะกดแป้นทุกครั้งการสาธิตก็จะประกอบด้วยสองไฟล์: และ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 ไม่มีประโยชน์ใดที่เกี่ยวข้องกับการปฏิบัติจริงที่นี่ หวังว่าฉันจะเห็นกรณีการใช้งานขั้นสูงในอนาคต :)
เรียนรู้เพิ่มเติม
สัญญาทั้งสองและสิ่งที่สังเกตได้จะช่วยให้เราทำงานกับฟังก์ชันแบบอะซิงโครนัสใน JavaScript พวกเขาจะคล้ายกันมากในหลายกรณีอย่างไรก็ตามยังมีความแตกต่างบางอย่างระหว่างทั้งสองเช่นกันสัญญาเป็นค่าที่จะแก้ไขในasynchronous
ลักษณะเช่นการโทรhttp บนมืออื่น ๆ , observables จัดการกับลำดับของเหตุการณ์ที่ไม่ตรงกัน ความแตกต่างที่สำคัญระหว่างพวกเขาอยู่ด้านล่าง:
สัญญาว่า:
สังเกต:
นอกจากนี้ฉันได้สร้างภาพกราฟิกสำหรับคุณด้านล่างเพื่อแสดงความแตกต่างด้วยสายตา:
Promise
เป็นวิธีที่ผิดที่จะคิดเกี่ยวกับสัญญา Promise
ความรับผิดชอบมันเท่านั้นที่จะประสบความสำเร็จในการจัดการหรือความล้มเหลวในทางที่เข้ากันได้ async .. ถ้าคุณต้องการที่จะยกเลิกการร้องขอ http คุณยกเลิกคำขอที่ไม่สัญญาและทำให้ผลของการยกเลิกทั้งตอบสนองหรือปฏิเสธสัญญา jsfiddle.net/greggman/ea0yhd4p
สัญญา
observables
ผู้ประกอบการหนึ่งลองใหม่อีกครั้งสามารถนำมาใช้เพื่อลองอีกครั้งเมื่อใดก็ตามที่จำเป็นถ้าเราต้องลองส่งใหม่ที่สังเกตได้ขึ้นอยู่กับเงื่อนไขบางอย่างretryWhenสามารถนำมาใช้
หมายเหตุ : รายชื่อผู้ประกอบการพร้อมกับไดอะแกรมแบบโต้ตอบมีให้ที่นี่ที่RxMarbles.com
มีข้อเสียอย่างหนึ่งของ Observables ที่ขาดหายไปในคำตอบ สัญญาอนุญาตให้ใช้ฟังก์ชัน async / await ของ ES7 คุณสามารถเขียนโค้ดแบบอะซิงโครนัสได้เพราะมันจะเป็นการเรียกฟังก์ชั่นซิงโครนัสดังนั้นคุณไม่จำเป็นต้องโทรกลับอีก ความเป็นไปได้เพียงอย่างเดียวสำหรับ Observables ในการทำเช่นนี้คือการแปลงเป็นสัญญา แต่เมื่อคุณแปลงเป็นสัญญาคุณสามารถมีค่าตอบแทนได้เพียงครั้งเดียว:
async function getData(){
const data = await observable.first().toPromise();
//do stuff with 'data' (no callback function needed)
}
อ่านเพิ่มเติม: ฉันจะ "รอ" ใน Rx Observable ได้อย่างไร
สัญญาและ Observables ทั้งสองจัดการการโทรแบบอะซิงโครนัสเท่านั้น
นี่คือความแตกต่างระหว่างพวกเขา:
น่าติดตาม
คำมั่นสัญญา
ปล่อยเพียงครั้งเดียวค่า
โทรหาบริการที่ไม่มี. then and .catch
ไม่สามารถยกเลิกได้
ไม่ได้ให้บริการตัวดำเนินการใด ๆ
แม้ว่าคำตอบนี้จะสาย แต่ฉันได้สรุปความแตกต่างด้านล่าง
สังเกต:
function
ที่ต้องทำan observer
และคืนค่า function Observer: an object with next, error.
subscribe/unsubscribe
สตรีมข้อมูลปล่อยค่าถัดไปไปยังผู้notify
สังเกตการณ์ผู้สังเกตการณ์errors
และแจ้งผู้สังเกตการณ์เกี่ยวกับstream completion
function to handle next value
ข้อผิดพลาดและจุดสิ้นสุดของสตรีม (กิจกรรม ui การตอบสนอง http ข้อมูลที่มีเว็บซ็อกเก็ต)multiple values
เมื่อเวลาผ่านไปcancel-able/retry-able
และสนับสนุนผู้ประกอบการเช่นmap,filter,reduce
ฯลฯObservable.create()
- return Observable ที่สามารถเรียกใช้เมธอด on - Observer Observable.from()
- แปลง array หรือ iterable เป็น - Observable Observable.fromEvent()
- แปลงเหตุการณ์เป็น Observable - Observable.fromPromise()
- แปลง Promise เป็น Observable - Observable.range()
- ส่งคืนลำดับของจำนวนเต็มในช่วงที่กำหนดสัญญา :
คำสัญญาหมายถึงภารกิจที่จะเสร็จสิ้นในอนาคต
สัญญากลายเป็นresolved by a value
;
สัญญาได้รับการปฏิเสธโดยข้อยกเว้น;
ไม่cancellable
และมันจะกลับมาa single value
คำสัญญาเปิดเผยฟังก์ชั่น (then)
ผลตอบแทน -then ใหม่ promise
;
- อนุญาตให้attachment
มีการดำเนินการตาม
state
;
- handlers
จะ guaranteed
ต้องดำเนินการในorder attached
;
ฉันเพิ่งจะจัดการกับปัญหาที่สัญญาเป็นทางออกที่ดีที่สุดและฉันแบ่งปันให้กับทุกคนที่สะดุดในคำถามนี้ในกรณีที่มีประโยชน์ (นี่คือคำตอบที่ฉันต้องการก่อนหน้านี้):
ในโครงการ 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 นั้นสมบูรณ์แบบ
scan()
เพื่อสร้างกระแสข้อมูลที่สังเกตได้ตามลำดับ อย่างไรก็ตามวิธีการของคุณอาจชัดเจนและเข้าใจง่ายขึ้น
ฉันเชื่อว่าคำตอบอื่น ๆ ทั้งหมดควรกำจัดข้อสงสัยของคุณ อย่างไรก็ตามฉันแค่อยากจะเพิ่มสิ่งที่สังเกตได้นั้นขึ้นอยู่กับการเขียนโปรแกรมการใช้งานและฉันพบว่ามีประโยชน์มากกับฟังก์ชั่นที่มาพร้อมกับมันเช่น map, flatmap, ลด, zip ความสอดคล้องของเว็บที่ประสบความสำเร็จโดยเฉพาะอย่างยิ่งเมื่อมันขึ้นอยู่กับคำขอ API คือการปรับปรุงที่โหดร้าย
ฉันแนะนำอย่างยิ่งเอกสารนี้เนื่องจากเป็นเอกสารอย่างเป็นทางการของ reactiveX และฉันพบว่าเอกสารนั้นชัดเจนที่สุด
หากคุณต้องการเข้าร่วม observables ฉันจะแนะนำโพสต์ 3 ส่วนนี้: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
แม้ว่ามันจะมีความหมายสำหรับ RxJava แนวคิดนั้นเหมือนกันและได้รับการอธิบายอย่างดี ในเอกสาร reactiveX คุณมีสิ่งที่เทียบเท่าสำหรับแต่ละฟังก์ชัน คุณต้องมองหา RxJS
คุณสามารถใช้สิ่งที่สังเกตได้สำหรับจัดการกับพฤติกรรมแบบอะซิงโครนัสเสมอเนื่องจากสิ่งที่สังเกตได้มีฟังก์ชันการทำงานทั้งหมดที่สัญญาให้ไว้ (+ พิเศษ) อย่างไรก็ตามบางครั้งฟังก์ชันการทำงานพิเศษนี้ที่ข้อเสนอสังเกตไม่จำเป็น จากนั้นจะเป็นค่าใช้จ่ายเพิ่มเติมในการนำเข้าไลบรารีเพื่อใช้งาน
ใช้สัญญาเมื่อคุณมีการ ดำเนินการ 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()
วิธีการจะถูกเรียก
ใช้สิ่งที่สังเกตได้เมื่อมีกระแสข้อมูล (ของข้อมูล) ในช่วงเวลาที่คุณต้องได้รับการจัดการ กระแสเป็นลำดับขององค์ประกอบข้อมูลที่มีการเปิดให้บริการในช่วงเวลา ตัวอย่างของสตรีมคือ:
ในการสังเกตตัวเองจะถูกระบุไว้เมื่อเหตุการณ์ต่อไปเกิดขึ้นเมื่อมีข้อผิดพลาดเกิดขึ้นหรือเมื่อสังเกตจะเสร็จสมบูรณ์ จากนั้นเราสามารถสมัครรับข้อมูลนี้ซึ่งเปิดใช้งานได้และในการสมัครสมาชิกนี้เราสามารถส่งกลับได้ 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 สมัครเป็นสมาชิกมันจะโทรกลับที่สอดคล้องกันที่ส่งผ่านไปยังการสมัครสมาชิก
สัญญา - ระบุมูลค่าในอนาคตเดียว ไม่ขี้เกียจ ไม่สามารถยกเลิกได้ มันจะปฏิเสธหรือแก้ไข
สังเกตได้ - ระบุมูลค่าในอนาคตหลายรายการ ขี้เกียจ . ยกเลิกได้ มันมีวิธีการอื่น ๆ แผนที่สดกรองลด
const promise = new Promise(resolve => {
setTimeout(() => {
resolve("Hello from a Promise!");
}, 2000);
});
promise.then(value => console.log(value));
ตัวอย่างที่สังเกตได้ในขณะนี้ ที่นี่เราผ่านฟังก์ชั่นเพื่อให้สังเกตได้ผู้สังเกตการณ์ในการจัดการงาน async แตกต่างจากการแก้ไขในสัญญามันมีวิธีการดังต่อไปนี้และสมัครสมาชิกแทน
ดังนั้นทั้งสองจัดการงาน async ตอนนี้เรามาดูความแตกต่าง
const observable = new Observable(observer => {
setTimeout(() => {
observer.next('Hello from a Observable!');
}, 2000);
});
observable.subscribe(value => console.log(value));
คำมั่นสัญญา
น่าติดตาม
ทั้งสัญญาและสิ่งที่สังเกตได้ช่วยให้เราจัดการกับการดำเนินการแบบอะซิงโครนัส พวกเขาสามารถเรียกกลับบางอย่างเมื่อการดำเนินการแบบอะซิงโครนัสเหล่านี้เสร็จสิ้น
Angular ใช้ Observables ซึ่งมาจาก RxJS แทนที่จะสัญญาว่าจะจัดการกับ HTTP
Below are some important differences in promises & Observables.
คำสัญญาส่งเสียงเหตุการณ์เดียวเมื่อกิจกรรม 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:
สังเกต:
สัญญาส่งเสียงค่าเดียวในขณะที่สังเกตได้ปล่อยหลายค่า ดังนั้นในขณะที่จัดการคำขอ 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
ด้านล่างนี้เป็นข้อแตกต่างที่สำคัญในสัญญาและสิ่งที่สังเกตได้
คำมั่นสัญญา
น่าติดตาม
เพื่อความเข้าใจที่ดีขึ้นโปรดอ้างถึงhttps://stackblitz.com/edit/observable-vs-promises
ฉันเห็นผู้คนจำนวนมากที่ใช้อาร์กิวเมนต์ที่ 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
คำตอบสั้น ๆ :
เห็นได้ชัดคือดีกว่ามันมีคุณสมบัติสัญญาทั้งหมดรวมถึงคุณสมบัติพิเศษ
คำตอบยาว:
สัญญา:
สังเกต:
ในขณะที่คำตอบที่ยอมรับนั้นดีโดยทั่วไปฉันไม่คิดว่ามันจะเน้นว่าเมื่อต้องรับมือกับ 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
บางสิ่งบางอย่างที่ฉันพบเจอในการอ่านบทช่วยสอนครั้งแรกและเอกสารนั้นเป็นแนวคิดของการทำมัลติคาสต์
ตรวจสอบให้แน่ใจว่าคุณทราบว่าโดยค่าเริ่มต้นการสมัครรับข้อมูลหลายรายการจะทริกเกอร์การประหารหลายครั้งใน Observable การสมัครสมาชิกหลายรายการในการโทร HTTP ครั้งเดียว Observable จะเรียกการโทร HTTP ที่เหมือนกันหลายรายการยกเว้นคุณ.share()
(เปิดใช้งานการรับหลายผู้รับ)
คำสัญญาบังคับให้คุณจัดการกับสิ่งหนึ่งครั้งแกะข้อมูลจัดการข้อยกเว้นมีการสนับสนุนภาษาสำหรับสิ่งดีๆเช่น async / รอและเป็นเปลือยเปล่า
ผู้สังเกตการณ์มีระฆังและนกหวีดมากมาย แต่คุณต้องเข้าใจพลังที่คุณกำลังใช้งานหรืออาจถูกนำไปใช้ในทางที่ผิด
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
ของที่ระลึกมักจะถูกเปรียบเทียบกับสัญญา นี่คือความแตกต่างที่สำคัญ:
สิ่งที่สังเกตได้คือสิ่งที่ประกาศ; การคำนวณไม่เริ่มจนกว่าการสมัครสมาชิก สัญญาดำเนินการทันทีในการสร้าง สิ่งนี้ทำให้สิ่งที่สังเกตได้มีประโยชน์สำหรับการกำหนดสูตรอาหารที่สามารถเรียกใช้เมื่อใดก็ตามที่คุณต้องการผลลัพธ์
สิ่งที่สังเกตได้มีค่ามากมาย สัญญาให้หนึ่ง สิ่งนี้ทำให้สิ่งที่สังเกตได้มีประโยชน์ในการรับหลายค่าเมื่อเวลาผ่านไป
สังเกตได้แตกต่างระหว่างการผูกมัดและการสมัครสมาชิก สัญญามีเพียง. แล้ว () ส่วน สิ่งนี้ทำให้สิ่งที่สังเกตได้มีประโยชน์สำหรับการสร้างสูตรการแปลงที่ซับซ้อนที่ส่วนอื่น ๆ ของระบบใช้โดยไม่ทำให้งานต้องถูกดำเนินการ
Observables Subscription () รับผิดชอบการจัดการข้อผิดพลาด สัญญาผลักดันข้อผิดพลาดให้เด็กสัญญา สิ่งนี้ทำให้สิ่งที่สังเกตได้มีประโยชน์สำหรับการจัดการข้อผิดพลาดจากส่วนกลางและคาดการณ์ได้
นั่นคือความแตกต่างที่ง่ายที่สุดที่คุณอาจพบในเอกสาร ANGULAR.IO คำตอบที่เหลือจะได้รับโดยส่วนใหญ่ถูกต้องในสถานที่ของตัวเอง
สัญญาจะเน้นเฉพาะค่าเดียวหรือการแก้ไขที่สามารถสังเกตได้คือกระแสข้อมูล
สามารถยกเลิกของที่ระลึกได้ แต่สัญญานั้นไม่สามารถยกเลิกได้
คนที่รู้จักน้อยที่สุดอย่างน้อยก็สำหรับฉันคือ
Observables and Promises ช่วยให้เราทำงานกับฟังก์ชันแบบอะซิงโครนัสใน JavaScript / typescript พวกเขามีความคล้ายคลึงกันมากในหลายกรณีอย่างไรก็ตามยังมีความแตกต่างระหว่างพวกเขา
มีคำตอบมากมายในหัวข้อนี้อยู่แล้วดังนั้นฉันจะไม่เพิ่มคำตอบที่ซ้ำซ้อน
แต่สำหรับคนที่เพิ่งเริ่มเรียนรู้จากการสังเกตการณ์ / เชิงมุมและสิ่งมหัศจรรย์ที่จะใช้เปรียบเทียบกับสัญญาฉันขอแนะนำให้คุณเก็บทุกอย่างที่สังเกตได้และแปลงสัญญาที่มีอยู่ทั้งหมดในโครงการของคุณเป็นที่สังเกตได้
เพียงเพราะกรอบเชิงมุมเองและชุมชนก็ล้วนใช้ Observable ดังนั้นจะเป็นประโยชน์เมื่อคุณรวมบริการเฟรมเวิร์กหรือโมดูลของบุคคลที่สามและเชื่อมโยงทุกอย่างเข้าด้วยกัน
ในขณะที่ฉันขอบคุณ downvotes ทั้งหมด แต่ฉันก็ยังคงยืนยันความคิดเห็นของฉันข้างต้นยกเว้นบางคนแสดงความคิดเห็นที่เหมาะสมเพื่อแสดงรายการบางสถานการณ์ที่อาจยังคงมีประโยชน์ในโครงการ Angular ของคุณเพื่อใช้สัญญามากกว่า Observables
แน่นอนว่าไม่มีความคิดเห็นใดที่ถูกต้อง 100% ในทุกกรณี แต่อย่างน้อยฉันก็คิดว่า 98% ของเวลาสำหรับโครงการเชิงพาณิชย์ตามปกติที่ดำเนินการใน Angular Framework สังเกตได้เป็นวิธีที่เหมาะสม
แม้ว่าคุณจะไม่ชอบมันที่จุดเริ่มต้นของโปรเจ็กต์งานอดิเรกง่ายๆของคุณคุณก็จะรู้ว่าส่วนประกอบเกือบทั้งหมดที่คุณโต้ตอบด้วยใน Angular และเฟรมเวิร์กของบุคคลที่สามที่เป็นมิตรกับ Angular ส่วนใหญ่กำลังใช้ Observables แล้ว จบลงด้วยการเปลี่ยนสัญญาของคุณเป็น Observable เพื่อสื่อสารกับพวกเขา
ส่วนประกอบเหล่านั้นรวมถึง แต่ไม่ จำกัด เพียง: HttpClient, ตัวสร้างแบบฟอร์ม, โมดูล / กล่องโต้ตอบวัสดุเชิงมุม, Ngrx store / effects และ ngx-bootstrap
ในความเป็นจริงสัญญาจากเชิงมุมระบบนิเวศฉันจัดการกับในอดีตที่ผ่านมา 2 APP_INITIALIZER
ปี