我有一个调用多种服务方法的函数。该函数驻留在服务对象中,我需要从app.component.ts调用该服务对象,从那里我需要等到该函数完成以执行更多代码。我的问题是如何更改此代码的返回类型,以便可以从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??
});
我尝试在this.initializeRegistration()
行上添加一个“返回”,然后在return Observable.of(true);
上添加,并将方法签名更改为公共registerAndGetToken(): Observable<boolean>
。但它不喜欢它。说
“预订”类型不能分配给“可观察”类型。
“预订”类型中缺少属性“ _isScalar”。 [2322]
答案 0 :(得分:1)
您的订阅太多了。 :)
我曾经听说过一些有关Observables的好建议-“怀疑订阅中的订阅”。这是一个很好的建议,因为这可能意味着如果我这样做的话,我将错误地解决该问题。作为一般经验法则,我也倾向于不订阅服务,而是将其留给组件(或者更好的是留给组件的模板)。否则,内存泄漏的机会就太多了,试图确保我全部取消订阅。
对于您而言,我很高兴您指定rxjs 5.5,因为那是在引入.pipe运算符时开始的,我认为这将使您的代码更容易编写。我对您的代码不了解很多,因此,我提供的内容并不是剪切和粘贴的解决方案,而是作为示例,说明如何对其进行重构以从服务中删除所有订阅,并最终返回一个可观察到的,可以在您的组件中进行订阅,如您在问题中所述。
以下是您可以考虑的一些代码:
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');
}
})
)
}
更新-我想我会分享一些有关为什么要进行每个步骤的想法,以防万一。
initializeRegistration()
将成为可观察到的源(或外部)可观察事物,一旦完成,则renewToken()
将被映射到链中并提供最终结果作为返回的令牌。return
语句开始,因为此函数将全部用于设置单个可观察的链,该链可返回并可以从组件中进行预订。initializeRegistration()
开始。订阅组件后,该函数将被执行,并且链将等待继续进行,直到完成(或给出错误)。initializeRegistration
时隐式订阅renewToken()
,因此我们在原始函数中不需要嵌套的订阅模式。此运算符还将新的observable映射(在这种情况下,从match
返回的值映射到我们的链中。因此,我们不再沿tokenResult
传递,而现在沿链中的tap
传递。renewTokenCallback()
。这是我真的不了解您的业务逻辑的地方,在这方面可能是错误的。因为tap并不会真正影响整个链,而只是给我们一个可以执行某种副作用的插入点,所以我选择将其称为catchError
。取决于该函数的功能,这可能不是处理此问题的正确方法... renewToken()
,这是对来自else
的错误的检查callbackResult
-重要的是,我们从其中返回一个实际的可观察对象,可以将其合并映射回主链。我尚不清楚该可观察到的内容-在组件上出现一些消息,告诉它$("#addspan").click(function(){console.log($(this)[0].id);});
我希望这会有所帮助。