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

Ngrx中store数据未就绪时Resolver执行失败 如何重试或预加载数据

问题根因

Angular 路由 Resolver 的执行优先级高于 @ngrx/router-store 派发的ROUTER_REQUEST/ROUTER_NAVIGATION等路由action,直接访问详情页链接时,Resolver会先触发执行查询详情数据,此时加载基础数据的Effect还未执行,store中无对应的comics列表数据,Resolver的filter条件永远不满足,导致页面永久卡住。

解决方案一:改造Resolver,等待基础数据加载完成(推荐)

直接在Resolver中先等待基础数据加载完成,再执行后续的详情查询逻辑,无需修改现有Effect逻辑,改造成本最低:

export class ComicDetailResolver implements Resolve<ComicDetail> {
  constructor(private store: Store<State>) {
  }

  resolve(): Observable<ComicDetail> {
    // 先等待基础数据加载完成
    return this.store.pipe(
      select(isLoaded),
      filter(loaded => !!loaded), // 等isLoaded变为true才往下走
      take(1),
      // 再拿路由ID触发详情查询
      switchMap(() => this.store.pipe(select(getRouteID))),
      map((routeId: string) => {
        this.store.dispatch(AppActions.getComicDetail({ routeId }));
        return routeId;
      }),
      // 等待详情数据返回
      switchMap(() => this.store.pipe(select(getItem))),
      filter((comic: ComicDetail) => !!comic),
      first()
    );
  }
}
解决方案二:应用初始化阶段预加载基础数据

如果希望所有路由执行前都保证基础数据可用,可以通过Angular的APP_INITIALIZER钩子在应用启动时就加载基础数据,优先级高于路由解析:

  1. 首先在AppModule中添加初始化provider:
import { APP_INITIALIZER } from '@angular/core';

// 初始化加载函数
export function preloadBaseData(store: Store<State>): () => Observable<any> {
  return () => store.pipe(
    select(isLoaded),
    tap(loaded => {
      if (!loaded) {
        // 新增一个触发加载数据的action,原有加载Effect逻辑可以复用
        store.dispatch(AppActions.triggerLoadData());
      }
    }),
    filter(loaded => !!loaded),
    take(1)
  );
}

// AppModule的providers中添加配置
@NgModule({
  // ... 其他配置保持不变
  providers: [
    { provide: Window, useValue: window },
    {
      provide: APP_INITIALIZER,
      useFactory: preloadBaseData,
      deps: [Store],
      multi: true
    }
  ],
})
export class AppModule { }
  1. 可以删掉原来监听路由action触发加载数据的Effect,或者保留做降级兼容。
原有重试代码无效的原因
  • Resolver要求必须返回Observable/Promise,你之前的代码直接调用了subscribe,没有返回流对象,路由会直接判定Resolver执行完成,不会等待异步逻辑
  • throwError用法错误,throwError需要接收错误值,不需要包裹of(),你之前的写法不会触发流报错,retry操作符根本不会被触发
  • 重试逻辑没有加延迟,三次重试会瞬间跑完,还是等不到Effect加载数据完成

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 00:06:01