Angular 2如何在函数外部访问服务返回的数据?
解决TypeScript函数外部访问异步返回数据的问题
嘿,我来帮你搞定这个问题!你的核心困扰是异步数据的访问时机——reloadFilms里的subscribe和then都是异步操作,直接在函数外部访问this.films大概率会拿到初始值或者undefined,因为异步流程还没执行完。下面给你几个实用的解决方案:
方案1:将reloadFilms封装为返回Promise的函数
把整个异步流程包装成Promise,这样外部可以通过async/await或者.then()来等待数据就绪:
reloadFilms(params): Promise<any[]> { this.spinnerService.show(); return new Promise((resolve, reject) => { this._productListService.getProductList().subscribe({ next: (productListData) => { this.filmResource.query(params) .then(() => { this.films = productListData; this.spinnerService.hide(); this.dtTrigger.next(); resolve(this.films); // 将数据传递出去 }) .catch(err => { this.spinnerService.hide(); reject(err); // 处理Promise异常 }); }, error: (err) => { this.spinnerService.hide(); reject(err); // 处理Observable异常 } }); }); }
外部调用方式:
// 方式A:用async/await(需要在async函数内使用) async fetchFilms() { try { const films = await this.reloadFilms(yourParams); // 这里可以直接使用films数据 console.log(films); } catch (err) { // 处理错误 } } // 方式B:用.then() this.reloadFilms(yourParams) .then(films => { // 处理films数据 console.log(films); }) .catch(err => { // 处理错误 });
方案2:用RxJS BehaviorSubject实现响应式数据共享
如果需要在多个地方监听数据变化,推荐用BehaviorSubject来存储数据,外部通过订阅Observable获取最新值:
首先在组件类中定义Subject:
import { BehaviorSubject } from 'rxjs'; // ... private filmsSubject = new BehaviorSubject<any[]>([]); // 初始值为空数组 public films$ = this.filmsSubject.asObservable(); // 暴露给外部订阅的Observable
然后修改reloadFilms:
reloadFilms(params) { this.spinnerService.show(); this._productListService.getProductList().subscribe({ next: (productListData) => { this.filmResource.query(params) .then(() => { this.films = productListData; this.filmsSubject.next(this.films); // 发射最新数据 this.spinnerService.hide(); this.dtTrigger.next(); }); }, error: (err) => { this.spinnerService.hide(); // 可选:发射错误或者处理异常 } }); }
外部订阅获取数据:
// 在需要的地方订阅films$ this.films$.subscribe(films => { // 每次数据更新都会触发这里,拿到最新的films console.log(films); });
方案3:通过回调函数传递数据
如果只是偶尔需要在调用reloadFilms时获取数据,可以添加一个回调参数:
reloadFilms(params, callback?: (films: any[]) => void) { this.spinnerService.show(); this._productListService.getProductList().subscribe({ next: (productListData) => { this.filmResource.query(params) .then(() => { this.films = productListData; this.spinnerService.hide(); this.dtTrigger.next(); // 调用回调传递数据 if (callback) callback(this.films); }); }, error: (err) => { this.spinnerService.hide(); // 可选:回调中传递错误 } }); }
调用方式:
this.reloadFilms(yourParams, (films) => { // 这里可以直接使用films数据 console.log(films); });
额外优化:简化异步嵌套
你当前的代码存在Observable和Promise嵌套的情况,可以用RxJS的switchMap操作符简化流程,让代码更清晰:
import { switchMap } from 'rxjs/operators'; import { from } from 'rxjs'; // ... reloadFilms(params): Promise<any[]> { this.spinnerService.show(); return this._productListService.getProductList().pipe( switchMap(productListData => { // 将Promise转为Observable,方便链式操作 return from(this.filmResource.query(params)).pipe( // 无论query结果如何,都返回productListData switchMap(() => [productListData]) ); }) ).toPromise() .then(films => { this.films = films[0]; this.spinnerService.hide(); this.dtTrigger.next(); return this.films; }) .catch(err => { this.spinnerService.hide(); throw err; }); }
内容的提问来源于stack exchange,提问作者codelover
相关产品推荐
相关产品推荐

