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()
};
}
吹我创建了锅炉模板工作(承诺)代码段,它允许轻松使用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>
使用嵌套 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>
当想要组合多个观测值时,你应该用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();