Редактировать
Это зависит от опции observe
, о которой я забыл в своем первоначальном ответе.
Observable<Book> = httpClient.get<Book>('/api/books/1', {
observe: 'body' // Default
});
Observable<HttpResponse<Book>> = httpClient.get<Book>('/api/books/1', {
observe: 'response'
});
Observable<HttpEvent<Book>> = httpClient.get<Book>('/api/books/1', {
observe: 'events',
reportProgress: true,
responseType: 'json'
});
По умолчанию next()
- этовызывается с телом ответа, но вы можете изменить его с помощью опции observe
.
С помощью 'response'
Angular передает весь ответ со статусом, заголовками, телом и т. д. на next()
.Это по-прежнему происходит не более одного раза для каждого запроса.
При 'events'
Angular информирует вас о нескольких интересных событиях обмена запросом-ответом, передав соответствующий HttpEvent
в next()
.Например, HttpSentEvent
указывает, что запрос был отправлен полностью.У HttpHeaderResponse
есть все заголовки ответа, но нет содержимого.
Если вы также используете reportProgress: true
, ваша функция next()
будет даже получать HttpProgressEvent
с, которые указывают, сколько байтов загружено или загружено.
Таким образом, при наблюдении за событиями next()
действительно будет вызываться несколько раз.
В моем исходном ответе ниже я предполагаю, что вы наблюдаете тело.Ответ
Что касается результирующего Observable
HTTP-запроса, вы правы, каждая функция next()
будет вызываться не более одного раза.
Однако,Вы можете использовать несколько операторов RxJS для преобразования результирующего Observable
в другой оператор, функция которого next()
будет вызываться чаще.
Несколько примеров:
this.httpClient.get('/api/books/1').pipe(
map(book => book.title),
startWith('Initial value')
).subscribe({
// Will be called twice: First with "Initial value", then with actual book title
next: title => console.log(title)
});
this.httpClient.get('/api/books/1').pipe(
repeat(3) // Results in 3 requests
).subscribe({
// Will be called 3 times, once for each request
next: book => console.log(book)
});
// Suppose bookIdChanges is a Subject<number> that changes whenever
// the user selects another book
this.bookIdChanges.pipe(
// Whenever the ID changes, the corresponding book is loaded from the server.
// A previous request will be cancelled.
switchMap(id => this.httpClient.get('/api/books/${id}'))
).subscribe({
// Will be called whenever the ID changes, unless it changes again before
// the response has arrived.
next: book => console.log(book)
});
Это может быть очевиднымчто next()
вызывается здесь несколько раз, если вы знаете задействованные операторы.
Но в реальном проекте HTTP-запросы обычно выполняются в сервисных методах.Например, давайте переместим композицию bookIdChanges
и HTTP-запрос из последнего примера в класс обслуживания:
@Injectable()
export class BookService {
private bookIdChanges = new Subject<number>();
constructor(private: HttpClient) { }
public selectAsCurrentBook(id: number): void {
bookIdChanges.next(id);
}
public getCurrentBook(): Observable<Book> {
return this.bookIdChanges.pipe(
switchMap(id => this.httpClient.get<Book>('/api/books/${id}'))
);
}
}
Затем мы используем его в таком компоненте, как:
this.postsService.getCurrentBook().subscribe(book => {
// ... do something with book
});
По-прежнему существует несколько запросов и несколько вызовов next()
, но теперь все это скрыто внутри метода службы.Это хорошо, но вы должны четко указать это в названии и / или документации метода сервиса.
Вывод: да, HTTP-запрос возвращает Observable
, который испускается не более одного раза., но если вы не подписываетесь на него напрямую, а скорее на преобразованный Observable
, вы теряете эту гарантию.