如果我在一个可观察对象上使用tap rxjs运算符调用另一个可观察对象,我可以保证它在管道的其余部分之前完成吗?
这里的想法是让服务对后端进行http调用,如果登录良好,则创建一个cookie,然后将映射后的响应返回给使用方组件。我要先确保已添加cookie,然后再继续确保没有任何竞争条件。
import { of, Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
const httpObservable = loginAccount('fsdfds', 'fdsfsd');
httpObservable.subscribe(x => {
console.log(x);
});
function loginAccount(username, password): Observable<any> {
const httpResponse = of({ loggedIn: false, data: 'faketokenfrombackend' });
return httpResponse.pipe(
// Will this AWLAYS complete before map?
tap(resp => fakeLocalStorage('Do something with the result')),
// Will this AWLAYS complete before map?
tap(resp => fakeLocalStorage('Do something else with the result')),
map(resp => {
if (!resp.loggedIn)
return { success: false, message: 'really bad thing happened' };
else
return {success: true, message: 'WEEEEEE, it worked!'}
}));
}
function fakeLocalStorage(data: string): Observable<boolean> {
console.log('adding token to cookie');
return of(true);
}
上面的脚本按预期将其输出到控制台窗口,但是我可以依靠它吗?
adding token to cookie
adding token to cookie
{success: false, message: "really bad thing happened"}
答案 0 :(得分:1)
是的,RxJS将按顺序运行管道运算符。只要抽头运算符是同步的,它们就会在地图运算符运行之前完成。如果他们执行异步操作,则不会。
答案 1 :(得分:0)
tap
仅执行提供的功能,然后发出输入值。 tap
不会订阅Observable,因此当您执行tap(resp => fakeLocalStorage(..))
时,fakeLocalStorage(..)
返回的Observable不会被订阅。
如果您要在fakeLocalStorage(..)
内预订Observable,那么显然这将是一个异步操作。 fakeLocalStorage(..)
将立即返回并且tap
将发出(最有可能在fakeLocalStorage(..)
中订阅的Observable发出/完成)。
为确保在执行某些操作之前已完成其他可观察对象,您必须使用switchMap
之类的映射函数将它们链接起来。
import { map, switchMap, mapTo, last, ignoreElements, endWith } from 'rxjs/operators';
httpResponse.pipe(
// 'last()' just emits the last element which is mapped to the original response
// if your inner Observable just emits one time you can remove 'last()'
switchMap(resp => fakeLocalStorage('1').pipe(last(), mapTo(resp))),
// you could also map to the Observable that should be executed
// but ignore its output and append the input
switchMap(resp => fakeLocalStorage('2').pipe(ignoreElements(), endWith(resp))),
map(resp => {
if (!resp.loggedIn)
return { success: false, message: 'really bad thing happened' };
else
return { success: true, message: 'WEEEEEE, it worked!' }
})
);