简体   繁体   English

嵌套订阅的Angular Typescript返回类型

[英]Angular Typescript return type for nested subscriptions

I have a function which calls multiple service methods. 我有一个调用多种服务方法的函数。 This function resides in a service object, which i need to call from the app.component.ts, from there i need to wait until this functions is completed to execute more code. 该函数驻留在服务对象中,我需要从app.component.ts调用该服务对象,从那里我需要等到该函数完成以执行更多代码。 My question is how can i change the return type of this so that i can subscribe to it from app.component.ts My code is as below. 我的问题是我该如何更改其返回类型,以便可以从app.component.ts订阅它。我的代码如下。

public registerAndGetToken() {

   this.initializeRegistration().subscribe((match)=> {

   // if initialization is success then invoke callback function
   // initializationCallback() will return a boolean (synchronous function)

   const callbackResult = this.initializationCallback(match);

   if(callbackResult) {

       this.renewToken().subscribe((tokenResult)=> {

       //renewTokenCallback is a synchronous function
       this.renewTokenCallback();
       //what to return from here??
       }, 
      (tokenError) => {
      //what to return from here?? 
      });
   }
   else {
    // what to return from here??
   }
 },
(error) => {
 // what to return from here??
});

I tried to add a "return" on this.initializeRegistration() line and then return Observable.of(true); 我试图在this.initializeRegistration()行上添加“ return”,然后return Observable.of(true); this.initializeRegistration() and change the method signature to public registerAndGetToken(): Observable<boolean> . 并将方法签名更改为public registerAndGetToken(): Observable<boolean> But it doesn't like it. 但它不喜欢它。 Says

Type 'Subscription' is not assignable to type 'Observable'. 无法将“订阅”类型分配给“可观察”类型。
Property '_isScalar' is missing in type 'Subscription'. “预订”类型中缺少属性“ _isScalar”。 [2322] [2322]

You've got way too many subscribes. 您订阅的方式太多了。 :) :)

I heard some good advice once about Observables - "be suspicious of a subscribe within a subscribe". 我曾经听说过一些有关Observables的好建议-“怀疑订阅内的订阅”。 That's pretty good advice because it probably means I'm approaching the problem incorrectly if I am doing that. 这是一个很好的建议,因为这可能意味着如果我这样做的话,我将错误地解决该问题。 As a general rule of thumb I also tend not to subscribe within a service, but leave that for the component (or better yet just for the template of the component). 作为一般经验法则,我也倾向于不订阅服务,而是将其留给组件(或者更好的是留给组件的模板)。 Otherwise there is too much opportunity for memory leaks, trying to make sure I unsubscribe them all. 否则,内存泄漏的机会就太多了,试图确保我全部取消订阅。

In your case I am glad you specify rxjs 5.5 because that is when the .pipe operator was introduced and that will make your code significantly easier to write I think. 对于您的情况,我很高兴指定rxjs 5.5,因为那是在引入.pipe运算符时开始的,我认为这将使您的代码更容易编写。 There is much I do not know about your code, so I offer the following not as a cut-and-paste solution, but rather as an example of how to refactor this to take out all the subscribes from your service, and ultimately return an observable which can be subscribed to in your component, as you stated in your question. 我对您的代码不了解很多,因此,我提供的内容并不是剪切和粘贴的解决方案,而是作为示例,说明如何对其进行重构以从服务中删除所有订阅,并最终返回一个可观察到的,可以在您的组件中进行订阅,如您在问题中所述。

Here is some code you can think about: 这是您可以考虑的一些代码:

public registerAndGetToken() {
    return this.initializeRegistration().pipe( // <-- return an Observable
        catchError((error) => {
            // handle case when initializeRegistration gives back an error,
            // for example:
            return throwError(`initializeRegistration() threw error: ${error.message}`);
            // This assumes the error will be bubbled up to the component
        }),
        mergeMap((match) => {
            const callbackResult = this.initializationCallback(match);
            if(callbackResult) {
                return this.renewToken().pipe(
                    tap((tokenResult)=> {
                        // Your example never uses tokenResult for anything ...
                        // so I'll assume you actually want tokenResult to bubble
                        // up all the way your component as the result ...
                        this.renewTokenCallback(); // This makes no sense to me ...
                                                   // why have a callback here?
                    }),
                    catchError((tokenError) => {
                        // add code to handle renewToken() returning an error 
                        return tokenError;
                    })
                )
            }
            else {
                // return something that can be handled inside the component 
                // when callbackResult is false.
                // for example:
                return throwError('callbackResult is false');
            }
        })
    )
}

Update - I thought I'd share some thoughts about why for each step, in case that is helpful. 更新-我以为如果有帮助的话,我会就每个步骤的原因分享一些想法。

  • Overall structure is that when the component subscribes to this chain, initializeRegistration() will become the source (or outer) observable that kicks things off, and once that completes then renewToken() will be mapped into the chain and provide the ultimate result as the returned token. 总体结构是,当组件订阅此链时, initializeRegistration()将成为可观察到的源(或外部)可观察对象,一旦完成,则renewToken()将被映射到链中并提供最终结果作为返回的令牌。
  • Start with a return statement because this function will be all about setting up a single observable chain which is returned and can be subscribed to from the component. return语句开始,因为此函数将全部用于设置单个可观察的链,该链可返回并可以从组件中进行预订。
  • Next, start things off with initializeRegistration() . 接下来,从initializeRegistration() After the component subscribes, this function will get executed and the chain will wait to proceed until it completes (or gives an error). 组件订阅后,此函数将被执行,并且链将等待继续进行,直到完成(或给出错误)。
  • Next, check for an error. 接下来,检查错误。 This needs to be done at this point because we are about to map (change) the observable in the chain with mergeMap so before we do that we check the source observable for errors and deal with them. 这时需要完成此操作,因为我们将要使用mergeMap映射(更改)链中的可观察对象,因此在执行此操作之前,我们先检查可观察源中的错误并进行处理。
  • Next, mergeMap. 接下来,mergeMap。 This operator takes care of the 'subscribe up', implicitly subscribing to initializeRegistration when it is in turn subscribed to by the component, so we don't need that nested subscribe pattern in your original function. 该运算符负责“订阅”,在由组件依次订阅initializeRegistration时隐式订阅,因此我们在您的原始函数中不需要嵌套的订阅模式。 This operator also maps the new observable (in this case the returned value from renewToken() into our chain. Therefore we are no longer passing along match , we are now passing along tokenResult in the chain. 此运算符还将新的observable映射(在这种情况下,是从renewToken()返回的值renewToken()到我们的链中。因此,我们不再传递match ,而现在传递链中的tokenResult
  • Before placing the result back into the main chain we will pipe that through two additional operators (I do that here in a sub-chain rather than in the main chain because of the if-else logic): 在将结果放回主链之前,我们将通过两个附加运算符(通过if-else逻辑在这里在子链而不是在主链中)进行处理:
  • First sub-chain operator is tap . 第一个子连锁经营是tap Here is where I really don't understand your business logic and may be wrong in this. 这是我真的不了解您的业务逻辑的地方,在这方面可能是错误的。 Because tap doesn't really affect the chain at all but rather just gives us an insertion point where we can execute some sort of side effect, this is what I chose to call the renewTokenCallback() . 因为tap根本不会真正影响链,而只是给我们一个可以执行某种副作用的插入点,因此我选择将其称为renewTokenCallback() Depending what that function does this may not be the right way to handle this ... 取决于该函数的功能,这可能不是处理此问题的正确方法...
  • Next sub-chain operator is catchError , this is the check for errors from renewToken() 下一个子链运算符是catchError ,这是检查来自renewToken()错误的renewToken()
  • Now done with the sub-chain, that is returned and back to the main chain again 现在完成了子链,该子链将返回并再次返回主链
  • Finally is the else - it is important that we return an actual observable from within this else that can be mergeMapped back into the main chain. 最后就是else -重要的是,我们返回的实际观察到的从这个别人可以mergeMapped回到主链中。 What that observable should be is unclear to me - some message up to the component to tell it that something went wrong in the callbackResult 对我来说,可观察到的应该是不清楚的-组件上有一些消息,告诉它callbackResult出了点问题

I hope this helps. 我希望这有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM