将承诺转换为可观察值

时间:2020-05-20 11:50:57

标签: javascript rxjs

RxJS是一个非常不错的库,我想将下面的函数从Promises转换为Observables

    async function userGoods(userName) {
      let user = await userReqest(userName).toPromise();
      let home = await homeReqest(user.id).toPromise();
      let dog = home ? await dogReqest(user.id).toPromise() : null;

      let financeUSD = user.savings;
      if(home) financeUSD += home.price;
      if(dog) financeUSD += dog.price;

      return { 
        USD: financeUSD, 
        EUR: await usd2eurReqest(financeUSD).toPromise() 
      };
    }

Blow我创建了样板工作(承诺)代码段,该代码段可轻松使用rxjs(并可以复制为答案)。下面的代码段包含4个可观察到的api请求模拟(请勿更改)

// Simulated API Request observables
let d = rxjs.operators.delay(100);
let userReqest = (name) => rxjs.of({id:123, name:name, savings: 10000}).pipe(d);
let homeReqest = (userId) => rxjs.of({userId, color:"black", price: 1000000}).pipe(d);
let dogReqest = (userId) => rxjs.of({userId, name:"Pig", price: 1000}).pipe(d);
let usd2eurReqest = (money) => rxjs.of( money*1.1 ).pipe(d);

// How to write below function using obserwables (without Promises) ?
async function userGoods(userName) {
  let user = await userReqest(userName).toPromise();
  let home = await homeReqest(user.id).toPromise();
  let dog = home ? await dogReqest(user.id).toPromise() : null;
  
  let financeUSD = user.savings;
  if(home) financeUSD += home.price;
  if(dog) financeUSD += dog.price;

  return { 
    USD: financeUSD, 
    EUR: await usd2eurReqest(financeUSD).toPromise() 
  };
}


// --------
// TEST
// --------

// you can change this function to support observables instead await
async function run() {
  console.log("John goods", await userGoods("John"));
}

run();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>

当我自己开始转换时,我编写了部分嵌套代码,但不知道如何完成它-到目前为止,这就是我所做的(可能是我做错了丑陋的方式)

// Simulated API Request observables
let d = rxjs.operators.delay(100);
let userReqest = (name) => rxjs.of({id:123, name:name, savings: 10000}).pipe(d);
let homeReqest = (userId) => rxjs.of({userId, color:"black", price: 1000000}).pipe(d);
let dogReqest = (userId) => rxjs.of({userId, name:"Pig", price: 1000}).pipe(d);
let usd2eurReqest = (money) => rxjs.of( money*1.1 ).pipe(d);

async function userGoods(userName) {
  userReqest(userName).subscribe((user)=> {
    homeReqest(user.id).subscribe((home)=> {
       dogReqest(user.id).subscribe((dog)=> {
         console.log({dog});
         
      })
    })
  });  
  
  // I don't know what to do next here - ?
}


// --------
// TEST
// --------

// you can change this function to support observables instead await
async function run() {
  console.log("John goods", await userGoods("John"));
}

run();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>

2 个答案:

答案 0 :(得分:1)

使用嵌套的switchMap调用映射到下一个Observable,同时保持前一个Observable的值可访问。您可以将获取狗并映射到整个用户财务状况的代码移动到单独的函数中,以减少一些嵌套。然后使用swichMap来获取EUR,并再次使用嵌套的map来同时发射两个{ USD, EUR }

const { of } = rxjs;
const { map, switchMap, delay } = rxjs.operators;

// Simulated API Request observables
const d = 100
let userReqest = (name) => of({id:123, name:name, savings: 10000}).pipe(delay(d));
let homeReqest = (userId) => of({userId, color:"black", price: 1000000}).pipe(delay(d));
let dogReqest = (userId) => of({userId, name:"Pig", price: 1000}).pipe(delay(d));
let usd2eurReqest = (money) => of( money*1.1 ).pipe(delay(d));

function userFinance(user, home) {
  return (home ? dogReqest(user.id) : of(null)).pipe(
    map(dog => user.savings + (home ? home.price : 0) + (dog ? dog.price : 0))
  );
}

function userGoods(userName) {
  return userReqest(userName).pipe(
    switchMap(user => homeReqest(user.id).pipe(
      switchMap(home => userFinance(user, home))
    )),
    switchMap(USD => usd2eurReqest(USD).pipe(
      map(EUR => ({ USD, EUR }))
    ))
  );
}
// --------
// TEST
// --------

function run() {
  userGoods("John").subscribe(
    goods => console.log("John goods", goods)
  );
}

run()
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>

答案 1 :(得分:0)

当要合并多个可观察对象时,应该使用rxjs方式-即。使用switchMaphttps://rxjs-dev.firebaseapp.com/api/operators/switchMap)。然后,您可以使用Observable.toPromise()。订阅可观察对象是将其连接到“外部”世界(您的应用程序的其余部分)的方法

然后您在userGoods中的代码将如下所示(我没有对其进行测试,但您自己可以使用它)

const dog = userReqest(userName).pipe(
  switchMap((user) => homeRequest(user.id).pipe(
    switchMap((home) => (home ? dogRequest(user.id) : null),
  )),
).toPromise();