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

Angular中inject()生成多余实例的问题确认与解决咨询

Angular中inject()获取服务实例问题排查与解决

问题背景

我想确认在Angular中使用inject()是否会获取服务的不同实例,这会不会是我代码失效的原因。

我的路由配置代码如下:

{
        path: 'recipes',
        component: RecipesComponent,
        resolve: {data: () => inject(HttpService).fetchRecipes()},
        children: [
           // 子路由配置
        ]
},

HttpService的代码:

@Injectable({
    providedIn: 'root'
})
export class HttpService {
    constructor(private recipeService: RecipeService, private http: HttpClient, private authSerivce: AuthService) {}
    storeRecipes() {
        const recipes = this.recipeService.getRecipes()
        this.http.put('https://ng-recipe-shopping-f9c65-default-rtdb.firebaseio.com/recipes.json', recipes)
        .subscribe(respone => {
            console.log(respone)
        })
    }

    ngOnInIt() {

    }

    fetchRecipes() {
        let authId: string
        this.authSerivce.userCred.subscribe(authToken => {
            authId = authToken
        })
      return  this.http.get<Recipe[]>(`https://ng-recipe-shopping-f9c65-default-rtdb.firebaseio.com/recipes.json?auth=${authId}`)
        .pipe(map(recipes => {
            return recipes.map(recipe => {
                
                return {
                    ...recipe,
                    ingredients: recipe.ingredients ? recipe.ingredients : []
                }
            })
        }),
        tap(recipes => {
            this.recipeService.fetchRecipes(recipes)
        }))
    }
}

当前问题:在路由模块中调用fetchRecipes()时,authSerivce.userCred的订阅并未执行,但应用其他地方调用userCred.next(/* value */)是正常的。我怀疑是HttpService实例不一致导致的,想知道怎么解决。我是Angular新手,已经看了约60%的官方依赖注入文档,没找到解决方案。


问题分析与解决方案

1. inject()获取的实例是否为根实例?

不会存在实例不一致的问题。你的HttpService配置了providedIn: 'root',这意味着该服务由根注入器提供,无论用构造函数注入还是inject()方法,只要注入上下文未限定在组件/模块级别,获取的都是同一个全局根实例。所以实例不一致不是当前问题的根源。

2. 真正问题:异步竞态导致订阅未生效

你在fetchRecipes()中的逻辑存在异步顺序问题:先订阅userCred,然后立刻发起HTTP请求,但订阅是异步操作——当你调用http.get时,authId可能还没被赋值(要么userCred的next在订阅之后才触发,要么之前触发的值没被当前订阅捕获),导致请求参数错误,同时订阅的回调看起来没执行。

修正方法:用RxJS操作符把异步流串联起来,确保拿到有效authId后再发起请求:

fetchRecipes() {
  return this.authSerivce.userCred.pipe(
    // 只取第一个有效token,避免重复触发请求
    first(authToken => !!authToken),
    // 拿到token后切换到HTTP请求流
    switchMap(authId => {
      return this.http.get<Recipe[]>(`https://ng-recipe-shopping-f9c65-default-rtdb.firebaseio.com/recipes.json?auth=${authId}`)
    }),
    map(recipes => {
      return recipes.map(recipe => {
        return {
          ...recipe,
          ingredients: recipe.ingredients ? recipe.ingredients : []
        }
      })
    }),
    tap(recipes => {
      this.recipeService.fetchRecipes(recipes)
    })
  )
}

3. 额外注意点

  • 你的HttpService里的生命周期钩子拼写成了ngOnInIt,正确写法是ngOnInit,这个错误会导致钩子无法执行,建议修正。
  • 路由resolve中的函数返回Observable即可,Angular会自动订阅并完成resolve流程,无需手动订阅。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 09:57:38