RXJS 6 - 承诺
RXJS 6 - toPromise
我目前正在尝试将 Observable
转换为 Promise。但是当我调用该方法时,什么也没有发生。我正在使用 Angular 6.
服务
public create(form: StoryForm): Promise<void | string> {
const key: string = this.afStore.createId();
return this.auth.authState.pipe(map(res =>
<Story>{
title: form.title, content: form.content, createdAt: new Date(), sid: key,
uid: res.uid, username: res.displayName
}
)).toPromise().then((story: Story) =>
this.afStore.doc(`stories/${key}`).set(story).catch(err => err.message));
}
组件
public save() {
this.triedToSave = true;
if (this.storyForm.valid) {
this.storyService.create(this.storyForm.value)
.then(() => this.router.navigate(['/stories']))
.catch((err: string) => this.notify.danger(err));
}
}
保存应该做的是导航或至少显示错误。
授权
authstate 是如何实现的:returns 一些用户信息的可观察值。它在不同的服务中实现,如下所示:
public get authState(): Observable<firebase.User> {
return this.afAuth.authState;
}
编辑
让我感到困惑的是,如果我使用模拟对象,它就会突然起作用:
public create(form: StoryForm) {
const key: string = this.afStore.createId();
return of({uid: 'blubb', displayName: 'kdsjf', photoUrl: 'kjdfkjfd'}).pipe(map(user => {
return {
title: form.title, content: form.content, createdAt: new Date(), sid: key,
uid: user.uid, username: user.displayName, photoUrl: user.photoURL
} as Story;
})).toPromise();
}
但我想知道为什么 toPromise 在上面的例子中不起作用...
我猜没有任何反应,因为当您触发保存方法时,authState 没有任何结果。显然你期望 authState observable 或 Subject 总是会触发一些输出,这只是在特定情况下才会发生。
下面的代码创建了一个监听 authState 的 -new- observable。
return this.auth.authState.pipe(map(res =>
<Story>{
title: form.title, content: form.content, createdAt: new Date(), sid: key,
uid: res.uid, username: res.displayName
}
)).toPromise().then((story: Story) =>
this.afStore.doc(`stories/${key}`).set(story).catch(err => err.message));
这段代码仅由保存方法触发。我的猜测是 authState 要么是一个可观察的,要么是一个主题。只有在触发保存方法后向 authState 传递新值时,您的代码才会起作用。
您使用模拟对象的代码有效,因为您创建了一个可立即发出该值的可观察对象。
如果 authState 是主题:将其替换为 ReplaySubject(1)
如果它是一个 observable,您需要像这样将其发布为 ReplaySubject:
authState.pipe(
publishReplay(1),
refCount()
);
要完全了解发生了什么,请阅读这篇文章:
https://blog.mindorks.com/understanding-rxjava-subject-publish-replay-behavior-and-async-subject-224d663d452f
这是一篇 java 文章,但适用相同的原则。
但老实说,当我看到人们使用 toPromise 方法时,我感到很害怕 :)
如果你按预期使用它,你会更快地学习 rxjs!
如果我写这段代码,它看起来会像这样:
public save$: Subject<StoryForm> = Subject<StoryForm>();
private destroy$: Subject<any> = new Subject();
ngOnDestroy(): void {
this.destroy$.next();
}
onInit() {
// the (click) eventhandler in your GUI should call save$.next(storyForm)
// this will trigger this statement
this.save$.pipe(
// withLatestFrom will fetch the last value from an observable,
// it still needs to be a ReplaySubject or ReplaySubject for this to work though!
// it will pass an array down the pipe with the storyForm value, and the last value from authState
withLatestFrom(this.auth.authState),
// switchMap does the actual work: note that we do not return a value,
// but an observable that should that return a value soon, that is why we need switchMap!
switchMap(([storyForm, authInfo]) => {
// i am assuming the "set" method returns an observable
// if it returns a Promise, convert it using fromPromise
return this.afStore.doc(`stories/${key}`).set(story).pipe(
// catchError needs to be on your api call
catchError(err => console.log(err))
);
}),
// this will kill your subscriptino when the screen dies
takeUntil(this.destroy$)
).subscribe(value => {
// "value" will be the return value from the "set" call
this.router.navigate(['/stories']);
}
}
我目前正在尝试将 Observable
转换为 Promise。但是当我调用该方法时,什么也没有发生。我正在使用 Angular 6.
服务
public create(form: StoryForm): Promise<void | string> {
const key: string = this.afStore.createId();
return this.auth.authState.pipe(map(res =>
<Story>{
title: form.title, content: form.content, createdAt: new Date(), sid: key,
uid: res.uid, username: res.displayName
}
)).toPromise().then((story: Story) =>
this.afStore.doc(`stories/${key}`).set(story).catch(err => err.message));
}
组件
public save() {
this.triedToSave = true;
if (this.storyForm.valid) {
this.storyService.create(this.storyForm.value)
.then(() => this.router.navigate(['/stories']))
.catch((err: string) => this.notify.danger(err));
}
}
保存应该做的是导航或至少显示错误。
授权
authstate 是如何实现的:returns 一些用户信息的可观察值。它在不同的服务中实现,如下所示:
public get authState(): Observable<firebase.User> {
return this.afAuth.authState;
}
编辑
让我感到困惑的是,如果我使用模拟对象,它就会突然起作用:
public create(form: StoryForm) {
const key: string = this.afStore.createId();
return of({uid: 'blubb', displayName: 'kdsjf', photoUrl: 'kjdfkjfd'}).pipe(map(user => {
return {
title: form.title, content: form.content, createdAt: new Date(), sid: key,
uid: user.uid, username: user.displayName, photoUrl: user.photoURL
} as Story;
})).toPromise();
}
但我想知道为什么 toPromise 在上面的例子中不起作用...
我猜没有任何反应,因为当您触发保存方法时,authState 没有任何结果。显然你期望 authState observable 或 Subject 总是会触发一些输出,这只是在特定情况下才会发生。
下面的代码创建了一个监听 authState 的 -new- observable。
return this.auth.authState.pipe(map(res =>
<Story>{
title: form.title, content: form.content, createdAt: new Date(), sid: key,
uid: res.uid, username: res.displayName
}
)).toPromise().then((story: Story) =>
this.afStore.doc(`stories/${key}`).set(story).catch(err => err.message));
这段代码仅由保存方法触发。我的猜测是 authState 要么是一个可观察的,要么是一个主题。只有在触发保存方法后向 authState 传递新值时,您的代码才会起作用。
您使用模拟对象的代码有效,因为您创建了一个可立即发出该值的可观察对象。
如果 authState 是主题:将其替换为 ReplaySubject(1)
如果它是一个 observable,您需要像这样将其发布为 ReplaySubject:
authState.pipe(
publishReplay(1),
refCount()
);
要完全了解发生了什么,请阅读这篇文章: https://blog.mindorks.com/understanding-rxjava-subject-publish-replay-behavior-and-async-subject-224d663d452f
这是一篇 java 文章,但适用相同的原则。
但老实说,当我看到人们使用 toPromise 方法时,我感到很害怕 :) 如果你按预期使用它,你会更快地学习 rxjs!
如果我写这段代码,它看起来会像这样:
public save$: Subject<StoryForm> = Subject<StoryForm>();
private destroy$: Subject<any> = new Subject();
ngOnDestroy(): void {
this.destroy$.next();
}
onInit() {
// the (click) eventhandler in your GUI should call save$.next(storyForm)
// this will trigger this statement
this.save$.pipe(
// withLatestFrom will fetch the last value from an observable,
// it still needs to be a ReplaySubject or ReplaySubject for this to work though!
// it will pass an array down the pipe with the storyForm value, and the last value from authState
withLatestFrom(this.auth.authState),
// switchMap does the actual work: note that we do not return a value,
// but an observable that should that return a value soon, that is why we need switchMap!
switchMap(([storyForm, authInfo]) => {
// i am assuming the "set" method returns an observable
// if it returns a Promise, convert it using fromPromise
return this.afStore.doc(`stories/${key}`).set(story).pipe(
// catchError needs to be on your api call
catchError(err => console.log(err))
);
}),
// this will kill your subscriptino when the screen dies
takeUntil(this.destroy$)
).subscribe(value => {
// "value" will be the return value from the "set" call
this.router.navigate(['/stories']);
}
}