我正在为博客建立一个前端。我需要能够从API中获取一系列帖子,然后为每个帖子重新调用API以获取特色图像对象并将其附加到其父Post对象。最后返回完整Post对象的数组。用Observables很难找到解决这个问题的最佳方法。
到目前为止我所拥有的:
export class PostService {
private apiAddress: string = '/wp-json/wp/v2/posts';
private logger: Logger;
constructor (private httpService: HttpService, private loggerService: LoggerService) {
this.logger = loggerService.newLogger('PostService');
}
getPosts(category: Category, page: number = 1, pageSize: number = 10): Observable<Post[]> {
this.logger.log(`getPosts(id:${category.id}, ${page}, ${pageSize}) returned`);
return this.httpService.get(`${this.apiAddress}?categories=${category.id}&page=${page}&per_page=${pageSize}&orderby=date&order=desc`).map<Response, Post[]>((res) => {
let posts:Post[] = [];
let body = res.json();
for (var i = 0; i < body.length; i++) {
posts.push(new Post(body[i]));
}
this.logger.log(`getPosts(id:${category.id}, ${page}, ${pageSize}) returned ${posts.length} posts`);
return posts;
});
}
}
了解我喜欢做什么:
export class PostService {
private apiAddress: string = '/wp-json/wp/v2/posts';
private logger: Logger;
constructor (private httpService: HttpService, private loggerService: LoggerService) {
this.logger = loggerService.newLogger('PostService');
}
getPosts(category: Category, page: number = 1, pageSize: number = 10): Observable<Post[]> {
this.logger.log(`getPosts(id:${category.id}, ${page}, ${pageSize}) returned`);
return this.httpService.get(`${this.apiAddress}?categories=${category.id}&page=${page}&per_page=${pageSize}&orderby=date&order=desc`).map<Response, Post[]>((res) => {
let posts:Post[] = [];
let body = res.json();
for (var i = 0; i < body.length; i++) {
posts.push(new Post(body[i]));
}
this.logger.log(`getPosts(id:${category.id}, ${page}, ${pageSize}) returned ${posts.length} posts`);
return posts;
}).forEach((post, done) => {
this.httpService.get(`/wp-json/wp/v2/media/${post.featured_media}`).map<Request, Media>((res) => {
let body = res.json();
post.featured_image = new Media(body);
done(post);
});
});
}
}
我可能完全以错误的方式思考Observables。我很感激任何反馈。谢谢!
答案 0 :(得分:0)
我可以看到你为两个http请求获取帖子而另一个获取特色媒体
在这种情况下,不要发出两个http请求,为什么不调整后端来重新调整数据,如
postdata : [
{postid:1, postname:"something else,
children:[
{childid :1, childname:first child item},
{childid :2, childname:second child item}
]
} //this is a post with children items in it
{postid :2, postname: "numbsertwo",
children:[
...return like in the above
]
}
我希望你能得到我的想法然后你可以通过
轻松地完成它们 return this.httpService.get(`$urltoget`).map<Response, Post[]>((res) => {
let posts:Post[] = [];
let body = res.json();
for (var i = 0; i < body.length; i++) {
posts.push(new Post(body[i]));
//here loop through the children
}
return posts;
})
答案 1 :(得分:0)
我会沿着这些方向做点什么
getPosts(category: Category, page: number = 1, pageSize: number = 10) {
this.logger.log(`getPosts(id:${category.id}, ${page}, ${pageSize}) returned`);
return this.httpService.get(`${this.apiAddress}?categories=${category.id}&page=${page}&per_page=${pageSize}&orderby=date&order=desc`).map((res) => {
let posts:Post[] = [];
let body = res.json();
for (var i = 0; i < body.length; i++) {
posts.push(new Post(body[i]));
}
this.logger.log(`getPosts(id:${category.id}, ${page}, ${pageSize}) returned ${posts.length} posts`);
return posts;
}).
switchMap(posts => {
const requestsForImage = new Array<Observable>();
forEach(post => {
requestsForImage.push(this.httpService.get(`/wp-json/wp/v2/media/${post.featured_media}`).map(res => {
let body = res.json();
post.featured_image = new Media(body);
}
));
})
return Observable.combineLatest(requestsForImage).map(() => posts);
})
}
基本思想是发送第一个http请求以检索帖子,然后创建一个其他http请求的数组,每个帖子一个,以检索每个帖子的图像。由于http请求是Observable,因此您创建了一个Observable数组。
您可以将一个Observable数组合并到一个新的Observable中,该Observable在Array的所有Observable都发出时发出。这是通过combineLatest运算符实现的。
最后一个地图运算符用于确保订阅者收到的是由第一个http调用创建的帖子数组。
答案 2 :(得分:0)
您需要将第一个请求的响应转换为流,然后再执行另一个请求。
永远不要将rx编程与for循环混合,这是一种不好的做法
您的代码应如下所示:
url = `${this.apiAddress}?categories=${category.id}
&page=${page}&per_page=${pageSize}
&orderby=date&order=desc`
mediaUrl = `/wp-json/wp/v2/media/${post.featured_media}`;
getPosts(category: Category,
page: number = 1,
pageSize: number = 10): Observable<Post[]> {
return this.httpService.get(url)
.map(res => res.json())
.flatMap(posts => Observable.from(posts))
.map(post => new Post(post))
.flatMap(post=>
this.httpService.get(mediaUrl)
.map(res=>res.json())
.map(image=> Object.assign(post, {
featured_image: new Media(body)
})
)
).toArray();
}
在我解释我做了什么之前,让我告诉你如何调试它。
如果您不确定两个运营商之间发生了什么,请使用do
。
...
.map(res => res.json())
.do(data=> console.log(data))
.flatMap(
...
do
将只在控制台中打印数据并继续执行。
我在这里一步一步地做什么:
.map(res => res.json())
转换后的流,其中包含对res.json数据流的响应
.flatMap(posts => Observable.from(posts))
每个流都包含一个数组,我们不希望这样。我们想逐个采取每个项目。因此,将stream<data[]>
转换为stream<data>
.map(post => new Post(post))
将每个原始对象转换为post对象
.flatMap(post=>
现在对于每个obj,我们想要再做一次http调用。因此,使用flatMap,我正在进行http调用,获取响应并修改响应并将对象添加回流。
.map(image=> Object.assign(post, {
featured_image: new Media(body)
})
)
获取媒体响应并返回post对象,并添加一个新的参数featured_image
。