Angular - это отправка запросов от сервиса лучше, чем от компонента? - PullRequest
0 голосов
/ 24 апреля 2019

Мне интересно, должен ли я отправить запрос в угловой сервис? или я должен отправить его непосредственно из компонента?

Первый подход:

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));
    }
  }

Что означает, что запрос был отправлен из службы, а затем вернуть ответ в качестве обещания

Так какой же подход лучше? если это второй подход, можно отловить ошибку из сервиса и выбросить ее в компонент?

Ответы [ 2 ]

1 голос
/ 24 апреля 2019

Ну, как говорит 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>

Я переключил ваш код с обещания на наблюдаемые, потому что наблюдаемые являются одним из самых больших преимуществ использования Angular. Наблюдаемые могут быть отменены, хорошо читаются в шаблонах и многих других, которые я могу вспомнить за один день.


Наблюдаемые значения очень сильны, вы можете всегда иметь свежую информацию, основанную на других наблюдаемых. Посмотрите, это может дать вам некоторые идеи ...

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),
    );
  }
}
0 голосов
/ 24 апреля 2019

Рекомендуется использовать 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 подход к вашим услугам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...