如何跳过 .map ionic 4 observables 中的迭代
How to skip over an iteration in .map ionic 4 observables
我正在开发一个 Ionic 4 应用程序,它从 wordpress API 中提取 posts。我正在使用 mergeMap 和 forkjoin 获取特色图片,以便在 posts 主页上获得 posts 特色图片。
当有特色图片要获取时,以下代码工作正常,但如果没有特色图片,那么我只会从我的 throwError 中得到一个错误。我似乎无法记录错误。
ERROR Something went wrong ;)
这是我的 home.page.ts 个文件
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { LoadingController } from '@ionic/angular';
import { WordpressRestapiService, Post } from '../services/wordpress-restapi.service';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
categoryId: number;
private posts : Post[] = [];
constructor(
public loadingController: LoadingController,
private router: Router,
private wordpressService: WordpressRestapiService) { }
async ngOnInit() {
const loading = await this.loadingController.create();
await loading.present();
this.loadPosts().subscribe((posts: Post[]) => {
this.posts = posts;
loading.dismiss();
});
}
loadPosts() {
return this.wordpressService.getRecentPosts(this.categoryId);
}
openPost(postId) {
this.router.navigateByUrl('/post/' + postId);
}
}
这是我使用 wordpress 的服务文件 api
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, forkJoin, throwError, empty } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class WordpressRestapiService {
baseRestApiUrl: string = 'http://example.com/wp-json/wp/v2/';
constructor(private httpClient: HttpClient) { }
getRecentPosts(categoryId: number, page: number = 1): Observable<any[]> {
// Get posts by a category if a category id is passed
let category_url = categoryId ? ("&categories=" + categoryId) : "";
return this.httpClient.get(this.baseRestApiUrl + "posts?page=" + page + category_url).pipe(
map((res: any) => res),
mergeMap((posts: any[]) => {
if (posts.length > 0) {
return forkJoin(
posts.map((post: any) => {
if (post.featured_media === 0) {
console.log('fired');
post.media = {};
return new Post(post);
}
else {
return this.httpClient.get(this.baseRestApiUrl + "media/" + post.featured_media).pipe(
map((res: any) => {
let media: any = res;
post.media = new Media(media);
return new Post(post);
}),
catchError(error => {
return throwError('Something went wrong ;)');
})
);
}
})
);
}
return empty();
}),
catchError(error => {
return throwError('Something went wrong ;)');
})
);
}
}
export class Post {
author: number;
categories: number[];
comment_status: string;
content: object;
date: string;
date_gmt: string;
excerpt: object;
featured_media: number;
format: string;
guid: object;
id: number;
link: string;
media: object;
meta: object;
modified: string;
modified_gmt: string;
ping_status: string;
slug: string;
status: string;
sticky: boolean;
tags: number[];
template: string;
title: object;
type: string;
_links: object;
constructor(values: Object = {}) {
Object.assign(this, values);
}
}
export class Media {
date: string;
date_gmt: string;
guid: object;
id: number;
link: string;
modified: string;
modified_gmt: string;
slug: string;
status: string;
type: string;
title: object;
author: number;
comment_status: string;
ping_status: string;
meta: object;
template: string;
alt_text: string;
caption: object;
description: object;
media_type: string;
mime_type: string;
media_details: object;
post: number;
source_url: string;
constructor(values: Object = {}) {
Object.assign(this, values);
}
}
我检查了一下,如果 post.featured_media === 0
那么就 return post 否则调用 api 来获取特色图片,但这似乎从来没有 return post 秒。 console.log('fired')
被调用但 loadingCtrl 永远不会关闭并且 posts 永远不会显示。
如果不存在特色图像但 return 所有 post,我如何才能 return post.media 的空对象?
更新: 根据大卫所说,我已经更新了 WordpresRestapi 服务中的 getRecentPosts() 函数,内容如下。这给了我想要的结果。
getRecentPosts(categoryId: number, page: number = 1): Observable<any> {
// Get posts by a category if a category id is passed
let category_url = categoryId ? ("&categories=" + categoryId) : "";
return this.httpClient.get(this.baseRestApiUrl + "posts?page=" + page + category_url).pipe(
map((res: any) => res),
mergeMap((posts: Post[]) => {
if (posts.length > 0) {
return forkJoin(
posts.map((post: Post) => {
if (post.featured_media === 0) {
post.media = new Media;
return of(new Post(post));
}
else {
return this.httpClient.get(this.baseRestApiUrl + "media/" + post.featured_media).pipe(
map((res: any) => {
post.media = new Media(res);
return new Post(post);
}),
catchError(val => of(val))
);
}
})
);
}
return empty();
}),
catchError(val => of(val))
);
}
我认为问题在于您要将 Post 而不是 Post 的 Observable 添加到要传递给 forkJoin 的数组中。
你可以试试,
import { Observable, forkJoin, throwError, empty, of } from 'rxjs';
...
if (post.featured_media === 0) {
console.log('fired');
post.media = {};
return of(new Post(post));
}
在旁注中,我会避免那样使用 catchError。它本质上是吃掉任何 javascript 错误(以及不成功的 HTTP 响应)。这就是为什么在这种情况下您没有看到有用的错误。
参考资料:
(这些不是官方文档,但我发现它们更具可读性)
Stack overflow 认为这些链接是代码...
https://www.learnrxjs.io/operators/combination/forkjoin.html
https://www.learnrxjs.io/operators/creation/of.html
https://www.learnrxjs.io/operators/error_handling/catch.html
我正在开发一个 Ionic 4 应用程序,它从 wordpress API 中提取 posts。我正在使用 mergeMap 和 forkjoin 获取特色图片,以便在 posts 主页上获得 posts 特色图片。
当有特色图片要获取时,以下代码工作正常,但如果没有特色图片,那么我只会从我的 throwError 中得到一个错误。我似乎无法记录错误。
ERROR Something went wrong ;)
这是我的 home.page.ts 个文件
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { LoadingController } from '@ionic/angular';
import { WordpressRestapiService, Post } from '../services/wordpress-restapi.service';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
categoryId: number;
private posts : Post[] = [];
constructor(
public loadingController: LoadingController,
private router: Router,
private wordpressService: WordpressRestapiService) { }
async ngOnInit() {
const loading = await this.loadingController.create();
await loading.present();
this.loadPosts().subscribe((posts: Post[]) => {
this.posts = posts;
loading.dismiss();
});
}
loadPosts() {
return this.wordpressService.getRecentPosts(this.categoryId);
}
openPost(postId) {
this.router.navigateByUrl('/post/' + postId);
}
}
这是我使用 wordpress 的服务文件 api
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, forkJoin, throwError, empty } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class WordpressRestapiService {
baseRestApiUrl: string = 'http://example.com/wp-json/wp/v2/';
constructor(private httpClient: HttpClient) { }
getRecentPosts(categoryId: number, page: number = 1): Observable<any[]> {
// Get posts by a category if a category id is passed
let category_url = categoryId ? ("&categories=" + categoryId) : "";
return this.httpClient.get(this.baseRestApiUrl + "posts?page=" + page + category_url).pipe(
map((res: any) => res),
mergeMap((posts: any[]) => {
if (posts.length > 0) {
return forkJoin(
posts.map((post: any) => {
if (post.featured_media === 0) {
console.log('fired');
post.media = {};
return new Post(post);
}
else {
return this.httpClient.get(this.baseRestApiUrl + "media/" + post.featured_media).pipe(
map((res: any) => {
let media: any = res;
post.media = new Media(media);
return new Post(post);
}),
catchError(error => {
return throwError('Something went wrong ;)');
})
);
}
})
);
}
return empty();
}),
catchError(error => {
return throwError('Something went wrong ;)');
})
);
}
}
export class Post {
author: number;
categories: number[];
comment_status: string;
content: object;
date: string;
date_gmt: string;
excerpt: object;
featured_media: number;
format: string;
guid: object;
id: number;
link: string;
media: object;
meta: object;
modified: string;
modified_gmt: string;
ping_status: string;
slug: string;
status: string;
sticky: boolean;
tags: number[];
template: string;
title: object;
type: string;
_links: object;
constructor(values: Object = {}) {
Object.assign(this, values);
}
}
export class Media {
date: string;
date_gmt: string;
guid: object;
id: number;
link: string;
modified: string;
modified_gmt: string;
slug: string;
status: string;
type: string;
title: object;
author: number;
comment_status: string;
ping_status: string;
meta: object;
template: string;
alt_text: string;
caption: object;
description: object;
media_type: string;
mime_type: string;
media_details: object;
post: number;
source_url: string;
constructor(values: Object = {}) {
Object.assign(this, values);
}
}
我检查了一下,如果 post.featured_media === 0
那么就 return post 否则调用 api 来获取特色图片,但这似乎从来没有 return post 秒。 console.log('fired')
被调用但 loadingCtrl 永远不会关闭并且 posts 永远不会显示。
如果不存在特色图像但 return 所有 post,我如何才能 return post.media 的空对象?
更新: 根据大卫所说,我已经更新了 WordpresRestapi 服务中的 getRecentPosts() 函数,内容如下。这给了我想要的结果。
getRecentPosts(categoryId: number, page: number = 1): Observable<any> {
// Get posts by a category if a category id is passed
let category_url = categoryId ? ("&categories=" + categoryId) : "";
return this.httpClient.get(this.baseRestApiUrl + "posts?page=" + page + category_url).pipe(
map((res: any) => res),
mergeMap((posts: Post[]) => {
if (posts.length > 0) {
return forkJoin(
posts.map((post: Post) => {
if (post.featured_media === 0) {
post.media = new Media;
return of(new Post(post));
}
else {
return this.httpClient.get(this.baseRestApiUrl + "media/" + post.featured_media).pipe(
map((res: any) => {
post.media = new Media(res);
return new Post(post);
}),
catchError(val => of(val))
);
}
})
);
}
return empty();
}),
catchError(val => of(val))
);
}
我认为问题在于您要将 Post 而不是 Post 的 Observable 添加到要传递给 forkJoin 的数组中。
你可以试试,
import { Observable, forkJoin, throwError, empty, of } from 'rxjs';
...
if (post.featured_media === 0) {
console.log('fired');
post.media = {};
return of(new Post(post));
}
在旁注中,我会避免那样使用 catchError。它本质上是吃掉任何 javascript 错误(以及不成功的 HTTP 响应)。这就是为什么在这种情况下您没有看到有用的错误。
参考资料: (这些不是官方文档,但我发现它们更具可读性) Stack overflow 认为这些链接是代码...
https://www.learnrxjs.io/operators/combination/forkjoin.html
https://www.learnrxjs.io/operators/creation/of.html
https://www.learnrxjs.io/operators/error_handling/catch.html