作为一个初学者,我正在经历observables和promise之间的区别,有人说,一旦订阅者订阅,每次从http请求返回数据(Observable)时,它都可以获得对其下一个方法的回调。我无法重新创建这样的场景wheredata在流中返回,接下来被多次调用,我只能找到一个立即作为一个数据集返回的数组。有些人可以共享这样的场景,其中next()函数被多次调用单个请求。
编辑
这取决于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
s,它表示上传或下载的字节数。
因此,在观察事件时,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
,则会失去此保证。