ฉันจะ `รอ 'บน Rx Observable ได้อย่างไร?


111

ฉันต้องการรอคอยสิ่งที่สังเกตเห็นได้เช่น

const source = Rx.Observable.create(/* ... */)
//...
await source;

ความพยายามที่ไร้เดียงสาส่งผลให้การรอคอยแก้ไขทันทีและไม่ปิดกั้นการดำเนินการ

แก้ไข: รหัสเทียมสำหรับกรณีการใช้งานแบบเต็มของฉันคือ:

if (condition) {
  await observable;
}
// a bunch of other code

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


คุณไม่สามารถย้ายรหัสที่เหลือ (ซึ่งคุณต้องการรอแหล่งที่มา) ไปยัง.subscribe()การเรียกใช้วิธีการได้หรือไม่?
StriplingWarrior

คำตอบ:


133

awaitคุณต้องผ่านสัญญากับ เปลี่ยนเหตุการณ์ต่อไปที่สังเกตได้ให้เป็นสัญญาและรอคอยสิ่งนั้น

if (condition) {
  await observable.first().toPromise();
}

แก้ไขหมายเหตุ: คำตอบนี้เดิมใช้. take (1) แต่เปลี่ยนมาใช้. first () ซึ่งจะหลีกเลี่ยงปัญหาของ Promise ที่ไม่เคยแก้ไขหากสตรีมสิ้นสุดก่อนที่จะมีค่าเข้ามา


3
แทนที่จะใช้ (1) คุณสามารถใช้await observable.first().toPromise();?
apricity

15
@apricity หากไม่มีค่าเมื่อเสร็จสิ้นfirst()จะส่งผลให้ถูกปฏิเสธและ take(1)จะส่งผลให้สัญญาที่รอดำเนินการ
Estus Flask

6
@apricity @AgentME จริงๆแล้วคุณไม่ควรใช้อย่างใดอย่างหนึ่งtake(1)หรือfirst()ในกรณีเช่นนี้ เนื่องจากคุณคาดว่าจะมีเหตุการณ์หนึ่งเกิดขึ้นคุณควรใช้single()ซึ่งจะทำให้เกิดข้อยกเว้นหากมีมากกว่า 1 ในขณะที่ไม่ทิ้งข้อยกเว้นเมื่อไม่มี หากมีมากกว่าหนึ่งรายการอาจมีบางอย่างผิดปกติในรหัส / โมเดลข้อมูลของคุณเป็นต้นหากคุณไม่ใช้ single คุณจะต้องเลือกรายการแรกที่ส่งคืนโดยพลการโดยไม่มีการเตือนว่ามีมากกว่านั้น คุณจะต้องดูแลเพรดิเคตของคุณในแหล่งข้อมูลต้นน้ำเพื่อรักษาลำดับเดียวกันเสมอ
ntziolis

3
อย่าลืมนำเข้า:import 'rxjs/add/operator/first';
Stephanie

7
ตอนนี้ toPromise () เลิกใช้งานแล้วเราจะทำอย่างไร?
10

26

ก็จะต้องมี

await observable.first().toPromise();

ตามที่ระบุไว้ในความคิดเห็นก่อนหน้านี้มีความแตกต่างกันอย่างมากระหว่างtake(1)และfirst()ตัวดำเนินการเมื่อมีว่างเปล่าที่สังเกตได้

Observable.empty().first().toPromise()จะส่งผลให้เกิดการปฏิเสธEmptyErrorซึ่งสามารถจัดการได้ตามนั้นเพราะจริงๆแล้วไม่มีค่า

และObservable.empty().take(1).toPromise()จะทำให้ได้ความละเอียดด้วยundefinedค่า.


ที่จริงtake(1)จะไม่ให้คำสัญญาที่รอดำเนินการ undefinedมันจะให้สัญญาแก้ไขได้ด้วย
Johan t Hart

ขอบคุณที่สังเกตว่าถูกต้อง ฉันไม่แน่ใจว่าทำไมโพสต์จึงแตกต่างกันพฤติกรรมอาจเปลี่ยนไปในบางจุด
Estus Flask

8

คุณจะต้องสัญญาดังนั้นคุณจะต้องการที่จะใช้await toPromise()ดูนี้toPromise()สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ


5

หากtoPromiseเลิกใช้งานสำหรับคุณคุณสามารถใช้ได้.pipe(take(1)).toPromiseแต่อย่างที่คุณเห็นที่นี่ไม่ได้เลิกใช้งาน

ดังนั้นโปรดใช้toPromise(RxJs 6) ตามที่กล่าวไว้:

//return basic observable
const sample = val => Rx.Observable.of(val).delay(5000);
//convert basic observable to promise
const example = sample('First Example')
  .toPromise()
  //output: 'First Example'
  .then(result => {
    console.log('From Promise:', result);
  });

async / await ตัวอย่าง:

//return basic observable
const sample = val => Rx.Observable.of(val).delay(5000);
//convert basic observable to promise
const example = await sample('First Example').toPromise()
// output: 'First Example'
console.log('From Promise:', result);

อ่านเพิ่มเติมที่นี่

และโปรดลบการอ้างสิทธิ์ที่ไม่ถูกต้องนี้ว่าtoPromiseเลิกใช้แล้ว


1

ใช้ใหม่firstValueFrom()หรือlastValueFrom()แทนtoPromise()ซึ่งตามที่ระบุไว้ในที่นี้เลิกใช้แล้วโดยเริ่มใน RxJS 7 และจะถูกลบออกใน RxJS 8

import { firstValueFrom} from 'rxjs';
import { lastValueFrom } from 'rxjs';

this.myProp = await firstValueFrom(myObservable$);
this.myProp = await lastValueFrom(myObservable$);

สิ่งนี้มีอยู่ใน RxJS 7+

ดู: https://indepth.dev/rxjs-heads-up-topromise-is-being-deprecated/

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