我可以在Angular服务中使用一次性订阅http操作吗?这样做有什么缺点吗?
public async signInAsync(userName: string, password: string): Promise<void> {
try {
const token = await this.authenticate(userName, password).pipe(first()).toPromise();
this.signInCompleted(token);
} catch {
this.signInFailed();
}
}
为了使用OnPush更改检测策略并在服务内部保留“业务逻辑”,服务使用称为state$
的可观察的方式向组件公开值,然后组件通过异步管道订阅该值。只有服务功能才能通过调用this.patchState('actionName', {...})
更新状态。
protected signInCompleted(token: string): void {
this.localStorageService.setItem(LocalStorageKey.AUTH_TOKEN, token);
this.patchState('signInCompleted', {
isAuth: true,
token: token,
error: null
});
this.router.navigate([AppRoute.AUTH]);
}
因此,如果我使用HttpClient,则必须以某种方式订阅返回的observable。
我从简单的订阅开始:
protected signIn(...): void {
this.authenticate(..).subscribe(..);
}
但是后来,我意识到它是不可测试的,因为我不知道何时执行调用,并且async()
不知道可观察性。
为了使其可测试,我必须使其异步并转换为Promise,但是我不确定如果我订阅pipe(first()).toPromise()
是否有任何不利之处。
我也在考虑使用pipe(map(...)).pipe(catchError(...))
,但是我不知道如何将操作绑定到组件,或者它是否比以前的方法更好。
public signIn(userName: string, password: string): Observable<void> {
return this.authenticate(userName, password).pipe(map(...)).pipe(catchError(...));
}
答案 0 :(得分:0)
使用promise似乎不是一个好方法,而当需要更新的请求或组件被破坏时,使用observables很容易取消调用。我不得不说语法没有像Promise中的async / await一样清晰,有时也很难测试,但是取消非常有用(特别是如果您在自动完成组件中有用于搜索的API调用绑定到每个击键和依此类推)。
对于副作用处理,我建议创建一个新的运算符:
export function effect<T>(
completed?: (value: T) => void,
failed?: (error: any) => void
): OperatorFunction<T, void> {
return (observable$: Observable<T>): Observable<void> =>
observable$.pipe(
tap(completed, failed),
catchError(_ => of()),
map(() => {})
);
}
在服务中使用它:
public login(userName: string, password: string): Observable<void> {
return this.loginUsingPOST(userName, password).pipe(
effect(
token => this.loginCompleted(token),
error => this.loginFailed(error)
)
);
}
并仅订阅组件:
public submit(): void {
this.authService
.login(this.loginForm.value.userName, this.loginForm.value.password)
.pipe(this.untilDestroy())
.subscribe();
}
感谢@fridoo