将承诺转换为可观察的东西

问题描述 投票:0回答:2

RxJS是一个非常好的库,我想把下面的函数从 PromisesObservables

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

吹我创建了锅炉模板工作(承诺)代码段,它允许轻松使用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>
javascript rxjs
2个回答
1
投票

使用嵌套 switchMap 调用来映射到下一个Observable,同时保持上一个Observable的值可以访问。你可以把取狗和映射到整体用户财务的代码移到一个单独的函数中,以减少一些嵌套。然后使用 swichMapEUR 并使用嵌套的 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>

0
投票

当想要组合多个观测值时,你应该用rxjs的方式--即使用 switchMap (https:/rxjs-dev.firebaseapp.comapioperatorsswitchMap。). 然后你可以使用 Observable.toPromise(). 订阅观测值是连接到 "外部 "世界(其余的应用程序)的方式。

然后你的代码在 userGoods 会是这样的(我没有测试过,但你自己玩玩吧

const dog = userReqest(userName).pipe(
  switchMap((user) => homeRequest(user.id).pipe(
    switchMap((home) => (home ? dogRequest(user.id) : null),
  )),
).toPromise();
© www.soinside.com 2019 - 2024. All rights reserved.