作为一个初学者,我经历了可观察值和promise之间的区别,有人说,一旦订阅者被订阅,每次从http请求返回data(Observable)时,它都可以回调其下一个方法。我无法重新创建这样一种场景,即数据在流中返回,然后多次被调用,我所能找到的只是一个数组,该数组立即作为一个数据集返回。有人可以分享这样的情形吗?next()函数被单个请求多次调用。
答案 0 :(得分:1)
修改
这取决于我在原始答案中忘记的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()
确实会被多次调用。
在下面的原始答案中,我假设您观察身体。
原始答案
就HTTP请求的结果Observable
而言,您是正确的,每个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
,您将失去此保证。