Promise พฤติกรรมทั้งหมดกับ RxJS Observables?


90

ใน Angular 1.x บางครั้งฉันต้องhttpส่งคำขอหลายครั้งและทำบางอย่างกับคำตอบทั้งหมด Promise.all(promises).then(function (results) {...})ฉันจะโยนสัญญาทั้งหมดในอาร์เรย์และโทร

แนวทางปฏิบัติที่ดีที่สุดของ Angular 2 ดูเหมือนจะชี้ไปที่การใช้ RxJS Observableเพื่อทดแทนสัญญาในhttpคำขอ หากฉันมี Observables ที่แตกต่างกันสองรายการหรือมากกว่าที่สร้างขึ้นจากคำขอ http จะมีคุณสมบัติเทียบเท่ากับPromise.all()?

คำตอบ:


80

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

อยู่นอกขอบเขตเล็กน้อย แต่ในกรณีที่มันช่วยได้ในเรื่องของการผูกมัดสัญญาคุณสามารถใช้คำง่ายๆflatMap: Cf. RxJS Promise Composition (การส่งผ่านข้อมูล)


1
ถ้าฉันมี 2 เรียกหนึ่งคำสัญญาการคืนสินค้าและการกลับมาอีกครั้งที่สังเกตได้ฉันสามารถใช้ forkjoin ได้หรือไม่ หรือสัญญาทั้งหมด ()? หรือไม่มีเลยฉันต้องปล่อยให้ 2 ฟังก์ชันกลับมาเป็นแบบเดียวกันทั้งสัญญาหรือสังเกตได้?
Joe Sleiman

1
โปรดช่วยด้วย forkJoin ไม่ทำงานเมื่อสิ่งที่สังเกตได้ส่งผ่านเนื่องจากพารามิเตอร์ไม่ปล่อยค่าออกมา ฉันมี Observables เป็นโมฆะและยังคงต้องการใช้ฟังก์ชัน forkJoin แต่ใช้งานไม่ได้
Goga Koreli

19

อัปเดตพฤษภาคม 2019 โดยใช้ RxJs v6

พบว่าคำตอบอื่น ๆ มีประโยชน์และต้องการเสนอตัวอย่างสำหรับคำตอบที่ Arnaud นำเสนอเกี่ยวกับzipการใช้งาน

นี่คือตัวอย่างข้อมูลที่แสดงความเท่าเทียมกันระหว่างPromise.allrxjs zip(โปรดทราบด้วยว่าใน rxjs6 ตอนนี้ zip นำเข้าโดยใช้ "rxjs" ได้อย่างไรและไม่ใช่ตัวดำเนินการ)

import { zip } from "rxjs";

const the_weather = new Promise(resolve => {
  setTimeout(() => {
    resolve({ temp: 29, conditions: "Sunny with Clouds" });
  }, 2000);
});

const the_tweets = new Promise(resolve => {
  setTimeout(() => {
    resolve(["I like cake", "BBQ is good too!"]);
  }, 500);
});

// Using RxJs
let source$ = zip(the_weather, the_tweets);
source$.subscribe(([weatherInfo, tweetInfo]) =>
  console.log(weatherInfo, tweetInfo)
);

// Using ES6 Promises
Promise.all([the_weather, the_tweets]).then(responses => {
  const [weatherInfo, tweetInfo] = responses;
  console.log(weatherInfo, tweetInfo);
});

ผลลัพธ์จากทั้งสองเหมือนกัน การดำเนินการข้างต้นให้:

{ temp: 29, conditions: 'Sunny with Clouds' } [ 'I like cake', 'BBQ is good too!' ]
{ temp: 29, conditions: 'Sunny with Clouds' } [ 'I like cake', 'BBQ is good too!' ]

ทำงานให้ฉัน :)
Naveen Kumar V

12

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


1
สิ่งนี้ไม่ตรงกับความต้องการในปัจจุบันของฉัน แต่ฉันจะใช้มันเร็ว ๆ นี้
Corey Ogburn

5
ที่ไม่บรรลุพฤติกรรมเดียวกันกับ Promise.all () แต่คล้ายกับ Promise.any ()
Purrell

ถ้าฉันมี 2 เรียกหนึ่งคำสัญญาการคืนสินค้าและการกลับมาอีกครั้งที่สังเกตได้ฉันสามารถใช้ forkjoin ได้หรือไม่ หรือสัญญาทั้งหมด ()? หรือไม่มีเลยฉันต้องปล่อยให้ 2 ฟังก์ชันกลับมาเป็นแบบเดียวกันทั้งสัญญาหรือสังเกตได้?
Joe Sleiman

1
@JoeSleiman ช้าไปหน่อย แต่คุณสามารถเลือกข้าง: Observable.fromPromise ()ร่วมกับ Observable.zip ()หรือObserable.toPromise ()พร้อม Promise.all ()
Arnaud P

11

ในreactivex.io fork เข้าร่วมจริงชี้ไปที่Zipซึ่งทำงานให้ฉัน:

let subscription = Observable.zip(obs1, obs2, ...).subscribe(...);

"ซึ่งหมายความว่า forkJoin จะไม่ปล่อยออกมามากกว่าหนึ่งครั้งและจะเสร็จสมบูรณ์หลังจากนั้นหากคุณต้องการปล่อยค่าที่รวมกันไม่เพียง แต่เมื่อสิ้นสุดวงจรชีวิตของการสังเกตการณ์ที่ผ่านไปแล้วให้ลองใช้ combinationLatest หรือ zip แทน" rxjs-dev.firebaseapp.com/api/index/function/forkJoin
Jeffrey Nicholson Carré

3
forkJoin รอให้การสังเกตทั้งหมดสิ้นสุดลงในขณะที่ zip จะปล่อยอาร์เรย์เมื่ออินพุตทั้งหมดปล่อยค่าแรกออกมา zip อาจส่งเสียงหลายครั้ง หากคุณมีการโทรด้วย http จะไม่สร้างความแตกต่าง
hgoebl

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