我想知道我是否应该从角度服务发送请求?或者我应该直接从组件发送它?
第一种方法:
RestaurantService.ts
getRestaurants(): Promise<_Restaurant[]> {
return this.get("/restaurants").toPromise();
};
Restaurants.component.ts
loadRestaurants = async () => {
try {
this.restaurants = await this.restaurantService.getRestaurants();
} catch (exception) {
console.log(JSON.stringify(exception, null, 2));
}
}
这意味着请求是通过组件触发的。
第二种方法:
RestaurantService.ts
async getRestaurants(): Promise<_Restaurant[]> {
try {
const response: _Restaurant[] = await this.get("/restaurants").toPromise() as _Restaurant[];
return response;
} catch (exception) {
throw new Error(exception);
}
};
Restaurants.component.ts
loadRestaurants = async () => {
try {
this.restaurants = await this.restaurantService.getRestaurants();
} catch (exception) {
console.log(JSON.stringify(exception, null, 2));
}
}
这意味着从服务中发出请求然后将响应作为承诺返回
那么最好的方法是什么?如果它是第二种方法,可以从服务中捕获错误并将其抛给组件?
正如Angular doc所说,在服务中使用该逻辑更好,看看这个:
class Service {
constructor(public http: HttpClient) { }
getRestaurants(): Observable<Restaurant> {
return this.http.get<{ /* Specify HTTP response schema */ }>(url).pipe(
// Transformation to actual Restaurants at one place
map(data => data.map(restaurant => new Restaurant()),
// Handle error
catchError(err => {
logError(err);
throw err;
// Or...
return of([]); // Mock data not to crash app
}),
// If multiple subscription are made to same source, it won't do multiple http calls
shareReply(1),
);
}
}
class Component {
restaurants: Restaurant[] = [];
ngOnInit(): void {
// Prefered way
this.restaurants$ = this.service.getRestaurants().pipe(
// If, you pass error down, you'll be able to hendle it here...
catchError(err => {
return of([]);
}),
);
// Alternative
this.cleanUp = this.service.getRestaurants().subscribe(restaurants => {
this.restaurants = restaurants;
});
}
ngOnDestroy(): void {
this.cleanUp.unsubscribe();
}
}
HTML
<!-- Observable -->
<div *ngFor="let restaurant of restaurants$ | async">
{{restaurant | json}}
</div>
<!-- Non-Observable -->
<div *ngFor="let restaurant of restaurants">
{{restaurant | json}}
</div>
我已经将你的代码从promise转换为observable,因为observable是使用Angular的最大好处之一。可以取消Observables,在模板中可以很好地阅读,以及我可能会想到的其他许多其他内容。
Observable非常强大,您可以随时获得基于其他可观察信息的新信息。看看,它可能会给你一些想法......
interface ApiResponse<type> {
awaitingNewValues: boolean;
error: null | any;
response: type;
}
class Service {
currentRestaurantID = new BehaviourSubject(1);
currentRestaurantInfo: Observable<ApiResponse<Restaurant>>;
constructor(private http: HTTPClient) {
let latestRestaurants: ApiResponse<Restaurant | undefined> = {
awaitingNewValues: true,
error: null,
response: [],
};
currentRestaurantInfo = this.currentRestaurantID.pipe(
switchMap(restaurantID => {
return concat(
// This will notify UI that we are requesting new values
of(Object.assign({}, latestRestaurants, { awaitingNewValues: true })),
// The actual call to API
this.http.get(`${apiUrl}/${restaurantID}`).pipe(
// Wrap response in metadata
map(restaurant => {
return {
awaitingNewValues: false,
error: null,
response: restaurant,
}
}),
// Notify UI of error & pass error
catchError(err => {
return of({
awaitingNewValues: true,
error: err,
response: undefined,
});
}),
),
);
}),
// Save last response to be used in next api call
tap(restaurants => this.latestRestaurants = restaurants),
// Prevent calling API too many times
shareReplay(1),
);
}
}
最佳做法是使用Observable
RestaurantService.ts
getRestaurants(): Observable<_Restaurant[]> {
return this.get('/restaurants');
};
Restaurants.component.ts
import { Subscription } from 'rxjs';
sub: Subscription;
loadRestaurants(): void {
this.sub = this.restaurantService.getRestaurants()
.subscribe(result => {
this.restaurants = result;
}, exception => {
console.log(exception);
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
如果您需要修改响应,则应在服务中使用pipe
方法。