Angular 4如何在Resolver中返回多个Observable并实现数据预加载
实现Angular Resolver预加载图书馆列表及对应书籍数据
我来帮你搞定这个预加载需求!要实现先加载图书馆列表,再批量获取每个图书馆的书籍数据,并且所有数据在页面加载前完成预加载,咱们需要调整Resolver的逻辑,借助RxJS的操作符把两个异步请求流程串起来,具体实现如下:
1. 导入必要的RxJS操作符
首先要确保导入处理异步流的核心操作符,它们能帮我们实现“先获取列表,再并行请求书籍”的逻辑:
import { Injectable } from '@angular/core'; import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; import { UserService } from './../_services/index'; // 导入RxJS操作符 import { forkJoin, switchMap, map } from 'rxjs/operators'; import { Observable } from 'rxjs';
2. 修改Resolver的resolve方法
咱们要把原来只获取图书馆列表的逻辑,扩展成“获取列表 → 批量请求书籍 → 整合数据”的完整流程:
@Injectable() export class LibraryResolver implements Resolve<any> { constructor(private _userService: UserService) {} resolve(route: ActivatedRouteSnapshot): Observable<any> { // 第一步:先请求图书馆列表 return this._userService.getLibraryList().pipe( // 第二步:拿到列表后,切换到请求书籍的流 switchMap(libraries => { // 为每个图书馆创建一个获取书籍的请求,同时把图书馆信息和书籍数据合并 const bookRequests = libraries.map(library => this._userService.getLibraryBooks(library.id).pipe( map(books => ({ ...library, // 保留图书馆原有信息 books: books // 新增书籍字段 })) ) ); // 用forkJoin等待所有书籍请求完成,返回整合好的数组 return forkJoin(bookRequests); }) ); } }
3. 关键逻辑解释
- switchMap:用来切换异步流,等
getLibraryList返回结果后,再启动后续的书籍请求流程 - map(内层):把每个图书馆的原始数据和对应的书籍数据合并成一个对象,方便组件直接使用
- forkJoin:并行发起所有图书馆的书籍请求,等全部请求完成后,把结果以数组形式返回,确保所有数据预加载完成后才进入页面
4. 组件中使用预加载的数据
在组件里,你可以直接从路由的data属性中拿到预加载好的完整数据,不需要再调用服务:
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-libraries', templateUrl: './libraries.component.html' }) export class LibrariesComponent implements OnInit { librariesWithBooks: any[]; constructor(private route: ActivatedRoute) {} ngOnInit(): void { // 从Resolver获取预加载的数据,这里的`libraryData`是你在路由配置中指定的key this.librariesWithBooks = this.route.snapshot.data['libraryData']; // 现在你可以直接使用包含书籍的图书馆数据了 console.log(this.librariesWithBooks); } }
5. 路由配置(补充)
别忘了在路由配置中把这个Resolver关联到对应的路由,比如:
import { Routes, RouterModule } from '@angular/router'; import { LibrariesComponent } from './libraries.component'; import { LibraryResolver } from './library.resolver'; const routes: Routes = [ { path: 'libraries', component: LibrariesComponent, // 指定Resolver,key为libraryData,和组件中获取的key对应 resolve: { libraryData: LibraryResolver } } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class LibrariesRoutingModule { }
可选容错处理
如果担心某个图书馆的书籍请求失败导致整个预加载失败,可以给单个请求添加catchError处理,比如返回空书籍数组:
import { catchError } from 'rxjs/operators'; import { of } from 'rxjs'; // 在创建bookRequests时修改: const bookRequests = libraries.map(library => this._userService.getLibraryBooks(library.id).pipe( map(books => ({ ...library, books })), catchError(() => of({ ...library, books: [] })) // 请求失败时返回空书籍数组 ) );
内容的提问来源于stack exchange,提问作者hxdef
相关产品推荐
相关产品推荐

