Angular 7:如何在每次服务调用前执行方法并获取LocalStorage的Payload
Angular服务中异步获取localStorage数据的问题解决
咱们先弄明白为什么会出现这个问题:@ngx-pwa/local-storage的getItem()方法返回的是一个Observable,这是异步操作——构造函数里的subscribe并不会立即执行,而是等localStorage的读取操作完成后才会给this.payload赋值。但如果在这个异步操作完成前,你就调用了list()方法,那this.payload自然还是undefined。
正确的实现方式
这里给你两个实用的解决方案,你可以根据场景选择:
方案一:每次调用接口前确保拿到payload
直接在list()方法里先获取payload,再发起HTTP请求,用RxJS的switchMap操作符把这两个异步操作串起来:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import * as Globals from '../../globals'; import { Observable, switchMap } from 'rxjs'; import { LocalStorage } from '@ngx-pwa/local-storage'; @Injectable({ providedIn: 'root' }) export class RechargesService { constructor( private http: HttpClient, public localStorage: LocalStorage ) {} list(): Observable<any> { // 先读取payload,拿到后再发送POST请求 return this.localStorage.getItem("payload").pipe( switchMap(payload => { return this.http.post(Globals.url_api + "recharges/list", { "payload": payload }); }) ); } }
这样每次调用list()时,都会确保先拿到payload再发起请求,彻底避免时序问题。
方案二:缓存payload,避免重复读取localStorage
如果不想每次调用接口都去读localStorage,可以在服务里提前把payload的Observable缓存起来,后续方法直接复用:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import * as Globals from '../../globals'; import { Observable, shareReplay } from 'rxjs'; import { LocalStorage } from '@ngx-pwa/local-storage'; @Injectable({ providedIn: 'root' }) export class RechargesService { // 缓存payload的Observable private payload$: Observable<any>; constructor( private http: HttpClient, public localStorage: LocalStorage ) { // shareReplay(1)确保只读取一次localStorage,后续直接用缓存的值 this.payload$ = this.localStorage.getItem("payload").pipe(shareReplay(1)); } list(): Observable<any> { return this.payload$.pipe( switchMap(payload => { return this.http.post(Globals.url_api + "recharges/list", { "payload": payload }); }) ); } }
这个方案适合payload不会频繁变化的场景,既保证了时序正确,又减少了localStorage的读取次数。
关于服务构造函数的逻辑问题
其实在服务的构造函数里写初始化逻辑是没问题的,但要注意异步操作的时序风险。你之前的问题就出在:构造函数里的异步赋值还没完成,外部就调用了依赖这个值的方法。
一般来说,构造函数适合做同步初始化,或者像方案二那样创建缓存的Observable(因为创建Observable是同步的,订阅才是异步的)。但不要依赖构造函数里的异步操作去给类属性赋值——因为你没法控制外部调用方法的时机。
更稳妥的实践是:
- 把异步依赖项转换成Observable,用RxJS的操作符管理异步流
- 尽量避免在类属性中存储异步获取的值,而是通过Observable传递,确保时序始终正确
内容的提问来源于stack exchange,提问作者Leandro Castro
相关产品推荐
相关产品推荐

