有没有更有效的方式在 Typescript 的订阅中进行订阅 [英] Is There a More Efficient Way to Have a Subscription in a Subscription in Typescript

查看:24
本文介绍了有没有更有效的方式在 Typescript 的订阅中进行订阅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为 Angular 11Typescript 中编写一些代码,我需要从一个 observable 中获取数据,然后通过另一个调用来获取名称.获得名称后,我想将其附加到原始对象中.

I am writing some code, in Typescript for Angular 11, where I need to get data from one observable and then looping through that have another call to get the name. Once I get the name I want to append it to the original object.

例如我有两个 observables 和 getSelfPurchases() 返回:

For example I have two observables and getSelfPurchases() returns:

{
  id: 32
  user_id: 5
  script_id: 78
  pp_id: "76SDI89768UIHUIH8976"
},
{
  id: 33
  user_id: 4
  script_id: 79
  pp_id: "78FGGF78SDF78FSD"
}

第二个 getScriptDetails(32) 返回:

and the second one, getScriptDetails(32), returns:

{
  sname: "Spell Checker"
  author: 43
  price: 20.99
}

我已经成功地实现了我想做的事情,但我觉得它很草率且效率低下.我一直在阅读更多关于 RXJS 的东西,比如 switch map,但我不确定是否可以做这样的事情.或者也许我选择的方法已经是最好的.输入?

I have successfully achieved what I wanted to do but I feel like it is sloppy and inefficient. I've been reading more into RXJS stuff like switch map, but I am unsure if something like that can be done. Or maybe the method I chose is the best one already. Input?

this.userService.getSelfPurchases().subscribe(response => { // first observable
  this.purchases = response;

  this.purchases.forEach((purchase, index) => { // loop through our results
    this.scriptService.getScriptDetails(purchase.script_id).subscribe(responseTwo => { // second observable
      if (responseTwo[0] && responseTwo[0].sname !== undefined) {
        this.purchases[index].sname = responseTwo[0].sname; // append to our original purchases object
      }
    });
  });
});

推荐答案

您基本上不想嵌套订阅.这与其说是效率问题,不如说是可维护性、可扩展性和(最重要的)可读性.

You basically never want to nest subscriptions. It's not a matter of efficiency so much as it's a matter so much as maintainability, extendability, and (most importantly) readability.

嵌套订阅很快就会导致回调地狱.以这种方式绝望地迷失是非常简单的.虽然我想一切都有时间和地点.

Nested subscriptions quickly lead to call-back hell. It's surprisingly simple to get hopelessly lost that way. Though there's a time and place for everything I suppose.

这是您的代码 1-1 重新编写的代码,没有嵌套订阅.我将您的 purchases 数组映射到 getScriptDetails 调用数组,然后通过 merge 订阅该数组.

This is your code re-written 1-1 as you had it before, without nesting subscriptions. I map your array of purchases into an array of getScriptDetails calls and then subscribe to that array via merge.

this.userService.getSelfPurchases().pipe(
  tap(response => this.purchases = response),
  map(purchases => purchases.map((purchase, index) => 
    this.scriptService.getScriptDetails(purchase.script_id).pipe(
      map(responseTwo => ({index, responseTwo}))
    )
  )),
  mergeMap(scriptDetailsCalls => merge(...scriptDetailsCalls)),
).subscribe(({index, responseTwo}) => {
  if (responseTwo[0] && responseTwo[0].sname !== undefined) {
    // append to our original purchases object
    this.purchases[index].sname = responseTwo[0].sname; 
  }
});

您可以将上面的 map 和 mergeMap 合并为一个 mergeMap,如下所示:

You can combine the map and mergeMap above into a single mergeMap as follows:

this.userService.getSelfPurchases().pipe(
  tap(response => this.purchases = response),
  mergeMap(purchases => merge(...
    purchases.map((purchase, index) => 
      this.scriptService.getScriptDetails(purchase.script_id).pipe(
        map(responseTwo => ({index, responseTwo}))
      )
    ))
  )
).subscribe(({index, responseTwo}) => {
  if (responseTwo[0] && responseTwo[0].sname !== undefined) {
    // append to our original purchases object
    this.purchases[index].sname = responseTwo[0].sname; 
  }
});


旁白:避免使用全局变量

这是对功能性纯度"的个人品味,但是避免设置全局变量然后稍后修改它的模式通常更干净.使测试变得更加困难,因为它使您对该全局变量的状态的保证较少.


Aside: Avoid global variables

It's a personal taste for functional "purity," but it's generally cleaner to avoid the pattern where you set a global variable and then modify it later. Makes testing it harder as it leaves you with fewer guarantees about the state of that global variable.

this.userService.getSelfPurchases().pipe(
  mergeMap(purchases => forkJoin(
    purchases.map(purchase => 
      this.scriptService.getScriptDetails(purchase.script_id).pipe(
        map(responseTwo => ({...purchase, sname: responseTwo[0].sname}))
      )
    )
  ))
).subscribe(purchasesWName =>
  this.purchases = purchasesWName
);

这篇关于有没有更有效的方式在 Typescript 的订阅中进行订阅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆