You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RxJS subscribe已弃用报错:Angular/Ionic星球大战列表代码问题

问题描述

开发Angular/Ionic星球大战角色列表页面时,调用ApiService的getStarwarsHeroes方法时,.subscribe出现划灰提示,提示该API已弃用。

相关代码

API服务代码

import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http';
import { Observable} from 'rxjs';

export interface ApiResult {
  page: number;
  results: any[];
  total_pages: number;
  total_results: number;
}

@Injectable({
  providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) {}

    getStarwarsHeroes(page:number =1): Observable<ApiResult> {
      return this.http.get<ApiResult>(`https://swapi.dev/api/people/${page}/`);
    }

    getStarwarsDetails(id:string): Observable<any>{
      return this.http.get<ApiResult>(
        `https://swapi.dev/api/people/${id}/`
      );
    }
}

页面TS代码

import { Component, OnInit } from '@angular/core';
import { ApiService} from '../api.service';
import { InfiniteScrollCustomEvent, LoadingController} from '@ionic/angular';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit { 

  starwars:any=[];
  currentPage:number= 1;

  constructor(
    private apiService:ApiService,
    private loadingCtrl: LoadingController
    ) {}

  ngOnInit() {
      this.loadStarwars();  
  }
    
  async loadStarwars(event?: InfiniteScrollCustomEvent) {
    const loading= await this.loadingCtrl.create({
      message: 'Loading..',
      spinner: 'bubbles',
    });
    await loading.present();
    
    this.apiService.getStarwarsHeroes(this.currentPage).subscribe(
      (res) => {
        loading.dismiss();
        this.starwars.push(...res.results);

 console.log(this.starwars);

        event?.target.complete();
        if (event) {
          event.target.disabled = res.total_pages === this.currentPage;
        }
      },
      (err) => {
        console.log(err);
        loading.dismiss();
      }
    );
  }

  loadMore(event: InfiniteScrollCustomEvent) {
      this.currentPage++;
      this.loadStarwars(event);
    }
}

页面HTML代码

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      StarWars Characters
    </ion-title>
    <ion-button slot="start">
    <ion-menu-button menu="main-menu"></ion-menu-button>
    </ion-button>
  </ion-toolbar>
</ion-header>

<ion-content>
 <ion-card 
 *ngFor='let item of starwars'
 [routerLink]="[item.id]"
 >
    <ion-card-header>
      <ion-card-title slot="start">{{item.name}}</ion-card-title>
    </ion-card-header>
    <ion-card-content slot="end">{{item.gender}}</ion-card-content>
  </ion-card>
</ion-content>

解决方案

原因说明

划灰提示源于RxJS 7+版本中,subscribe(next, error, complete)这种多参数回调的调用方式被标记为弃用,官方推荐使用观察者对象形式调用subscribe,或者在Angular项目中使用async管道自动管理订阅(更优方案,可避免手动订阅的内存泄漏问题)。

方案一:改用观察者对象调用subscribe

修改loadStarwars方法中的subscribe部分,将多参数回调改为对象形式:

async loadStarwars(event?: InfiniteScrollCustomEvent) {
  const loading= await this.loadingCtrl.create({
    message: 'Loading..',
    spinner: 'bubbles',
  });
  await loading.present();
  
  this.apiService.getStarwarsHeroes(this.currentPage).subscribe({
    next: (res) => {
      loading.dismiss();
      this.starwars.push(...res.results);
      console.log(this.starwars);
      event?.target.complete();
      if (event) {
        event.target.disabled = res.total_pages === this.currentPage;
      }
    },
    error: (err) => {
      console.log(err);
      loading.dismiss();
    }
  });
}

方案二:使用async管道优化(推荐)

此方式无需手动调用subscribe,Angular会自动处理订阅与取消订阅,避免内存泄漏:

  1. 修改页面TS代码,调整数据存储与分页逻辑:
import { Component, OnInit } from '@angular/core';
import { ApiService} from '../api.service';
import { InfiniteScrollCustomEvent, LoadingController} from '@ionic/angular';
import { Observable, concat, of } from 'rxjs';
import { catchError, finalize, map, tap } from 'rxjs/operators';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit { 
  starwars$: Observable<any[]>;
  private allResults: any[] = [];
  currentPage: number = 1;
  private isLastPage = false;

  constructor(
    private apiService: ApiService,
    private loadingCtrl: LoadingController
  ) {}

  ngOnInit() {
    this.loadStarwars();  
  }
    
  async loadStarwars(event?: InfiniteScrollCustomEvent) {
    if (this.isLastPage) {
      event?.target.complete();
      return;
    }

    const loading = await this.loadingCtrl.create({
      message: 'Loading..',
      spinner: 'bubbles',
    });
    await loading.present();

    const pageData$ = this.apiService.getStarwarsHeroes(this.currentPage).pipe(
      tap(res => {
        this.isLastPage = res.total_pages === this.currentPage;
        this.allResults.push(...res.results);
      }),
      map(() => this.allResults),
      catchError(err => {
        console.log(err);
        return of(this.allResults);
      }),
      finalize(() => {
        loading.dismiss();
        event?.target.complete();
        if (event) {
          event.target.disabled = this.isLastPage;
        }
      })
    );

    this.starwars$ = this.currentPage === 1 ? pageData$ : concat(this.starwars$, pageData$);
    this.currentPage++;
  }

  loadMore(event: InfiniteScrollCustomEvent) {
    this.loadStarwars(event);
  }
}
  1. 修改页面HTML代码,使用async管道:
<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      StarWars Characters
    </ion-title>
    <ion-button slot="start">
    <ion-menu-button menu="main-menu"></ion-menu-button>
    </ion-button>
  </ion-toolbar>
</ion-header>

<ion-content>
 <ion-card 
 *ngFor='let item of starwars$ | async'
 [routerLink]="[item.id]"
 >
    <ion-card-header>
      <ion-card-title slot="start">{{item.name}}</ion-card-title>
    </ion-card-header>
    <ion-card-content slot="end">{{item.gender}}</ion-card-content>
  </ion-card>
</ion-content>

内容的提问来源于stack exchange,提问作者Stefan Stahuber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:30:45