【发布时间】:2021-02-10 02:25:34
【问题描述】:
我正在编写一个服务,我打算存储 Place 对象的本地副本,并仅在它们未本地存储时从后端获取它们。但是,我在实现此功能时遇到了麻烦。如果来自place() 的值是undefined,我可以将我的页面设置为调用fetchPlace(),但我打算将fetchPlace() 保持私有,以便我以后可以实现一个系统来检查是否有请求是最近制作的,这样如果用户快速切换页面,服务器就不会被请求淹没。
places.service.ts
export class PlacesService {
private _places = new BehaviorSubject<Place[]>([]);
get places() {
return this._places.asObservable();
}
constructor(private _http: HttpClient) {}
place(placeId: number): Observable<Place> {
return this._places.pipe(
take(1),
map((places: Place[]) => {
console.log(places);
let place = places.find((place: Place) => place.id === placeId);
if (place === undefined) {
console.log('Time to send a request!');
this.fetchPlace(placeId).subscribe(
(fetchedPlace: Place) => {
console.log('We got one!');
place = fetchedPlace;
console.log(place);
},
(error) => {
console.error('Looks like a 404.');
},
);
}
console.log('Okay, returning place now!');
return place;
}),
);
}
private fetchPlace(placeId: number): Observable<Place> {
return this._http
.get<Place.ResponseBody>(`http://localhost:8000/v1/places/${placeId}/`)
.pipe(map((response: Place.ResponseBody) => Place.create(response)));
}
}
上面代码的问题是,当变量place为undefined时,对fetchPlace()的订阅被异步调用,所以place在place的值之前返回被fetchedPlace 覆盖。我想要某种方式从 place() 函数返回包含 place 的 observable。
为了完整起见,这里是上面代码的调用方式,以及控制台输出:
place-detail.page.ts
ngOnInit() {
this._route.paramMap.subscribe((paramMap: ParamMap) => {
if (!paramMap.has('placeId')) {
this._navCtrl.navigateBack('/places/discover');
return;
}
const placeId = +paramMap.get('placeId');
this._placesSub = this._placesSrv.place(placeId).subscribe(
(place: Place) => {
if (place === undefined) {
console.log('Got here.');
} else {
this._isBookable = place.user !== this._authSrv.user;
this._place = place;
}
},
(error) => {
console.error(error);
}
);
});
}
控制台
Angular is running in development mode. Call enableProdMode() to enable production mode. core.js:26833
Native: tried calling StatusBar.styleDefault, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator common.js:284
Native: tried calling SplashScreen.hide, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator common.js:284
[WDS] Live Reloading enabled. client:52
Array []
places.service.ts:81:16
Time to send a request! places.service.ts:85:18
Okay, returning place now! places.service.ts:98:16
Got here. place-detail.page.ts:75:20
We got one! places.service.ts:88:22
Object { _id: 1, _user: 2, _title: "Manhattan Mansion", _description: "In the heart of New York City.", _imgUrl: "https://www.idesignarch.com/wp-content/uploads/New-York-Fifth-Avenue-Mansion_1.jpg", _price: "149.99", _availableFrom: Date Fri Dec 31 2021 18:00:00 GMT-0600 (Central Standard Time), _availableTo: Date Sat Dec 30 2023 18:00:00 GMT-0600 (Central Standard Time) }
places.service.ts:90:22
【问题讨论】:
标签: angular rxjs rxjs-observables