Angular+RxJS异步订阅Observable后遍历存储数组为空问题
问题根源
你遇到的是典型的异步执行时序问题:RxJS封装的HTTP请求属于异步非阻塞任务,当前代码的实际执行顺序和你的预期完全不符:
- 调用
getUserInfosFav()时只会发起HTTP请求,不会阻塞代码等待接口返回,会立刻执行后续的同步代码 - 紧接着执行的
console.log(this.test)、loadFavoris()运行时,接口还没收到响应,test还是初始化的空数组,自然遍历不出任何内容 - 等所有同步代码执行完毕,接口耗时几百毫秒返回后,才会进入
subscribe的next回调往test里塞值,但这时候loadFavoris()早就执行完了。
另外你的代码还有一个隐藏问题:接口返回值本身就是用户数组,你用push(v)往test里塞值会生成嵌套结构[ [用户数据对象] ],后续取内部属性时很容易踩坑。
修复方案
所有依赖异步返回值的逻辑,必须放到请求完成后的异步回调里执行,给你两种常用实现:
方案1:回调内执行后续逻辑
改动最小,把后续处理逻辑挪到subscribe的next回调里,等数据赋值完成再调用:
export class FavoritesComponent implements OnInit { test: any[] = []; constructor(private userService: UserService) { } ngOnInit(): void { this.getUserInfosFav(); } getUserInfosFav() { const idUser = this.userService.decodeToken().id; this.userService.getUserInformations(idUser) .subscribe({ next: (v) => { // 直接赋值不要push,避免数组嵌套 this.test = v; // 数据赋值完成后再调用后续处理方法 this.loadFavoris(); }, error: (e) => console.error(e), complete: () => console.info('complete') }) } loadFavoris() { console.log(this.test) this.test.forEach(val => console.log(val)) // 这里可以正常拿到用户的收藏数据 const favoriteList = this.test[0]?.favorites || []; console.log('获取到的收藏项:', favoriteList); } }
方案2:RxJS链式流处理(更推荐)
符合RxJS的响应式编程规范,减少全局临时变量,用操作符直接在流内完成数据转换:
import { map, catchError, of } from 'rxjs'; export class FavoritesComponent implements OnInit { constructor(private userService: UserService) { } ngOnInit(): void { const idUser = this.userService.decodeToken().id; this.userService.getUserInformations(idUser) .pipe( map(res => { // 流内直接做数据处理、转换 const userInfo = res[0]; return userInfo.favorites; }), catchError(err => { console.error(err); return of([]); }) ) .subscribe(favorites => { // 直接拿到处理完成的收藏列表做后续逻辑 this.loadFavoris(favorites); }); } loadFavoris(favorites: any[]) { console.log(favorites); favorites.forEach(item => console.log(item)); } }
注意:Angular里如果是要把数据渲染到模板,也可以直接用
async管道订阅Observable,不用手动subscribe,还能自动避免内存泄漏。
内容的提问来源于stack exchange,提问作者kjod
相关产品推荐
相关产品推荐

