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

Angular用provideAppInitializer初始化RxDB报错:Database not initialized yet

Angular中使用App Initializer初始化RxDB时,组件调用getDatabase抛出"Database not initialized yet"错误

我是React开发者,现在尝试用Angular开发依赖RxDB的应用。我把RxDB封装在根服务DatabaseService中,在app.config.ts里通过provideAppInitializer调用服务的initDatabase方法初始化数据库,但最早访问数据的ItemsComponent调用getDatabase时抛出"Database not initialized yet"错误。相关代码如下:

相关代码

DatabaseService

import { Injectable } from '@angular/core';
import { createRxDatabase, RxDatabase } from 'rxdb';
import { ItemCollection, itemSchema } from '../items/items.schema';
import { getRxStorageMemory } from 'rxdb/plugins/storage-memory';

type MyDatabaseCollections = {
  items: ItemCollection;
};
type MyDatabase = RxDatabase<MyDatabaseCollections>;

@Injectable({
  providedIn: 'root',
})
export class DatabaseService {
  private static database: MyDatabase;

  constructor() {}

  async initDatabase(): Promise<void> {
    if (!DatabaseService.database) {
      const db = await createRxDatabase<MyDatabaseCollections>({
        name: 'mydb',
        storage: getRxStorageMemory(),
      });

      await db.addCollections({
        items: {
          schema: itemSchema,
        },
      });

      DatabaseService.database = db;
    }
  }

  getDatabase(): MyDatabase {
    if (!DatabaseService.database) {
      throw new Error('Database not initialized yet');
    }
    return DatabaseService.database;
  }
}

app.config.ts

providers: [
    DatabaseService,
    provideAppInitializer(() => inject(DatabaseService).initDatabase()),
  ],

ItemsComponent

@Component({
  selector: 'app-items',
  imports: [ToastModule],
  templateUrl: './items.component.html',
})
export class ItemsComponent {
  items: ItemType[] = [];

  constructor(
    private toastService: ToastService,
    private databaseService: DatabaseService,
  ) {
    this.getItems();
  }

  getItems() {
    const db = this.databaseService.getDatabase();
    const items = db.items.find().$;

    items.subscribe((docs) => {
      console.log(docs);
    });
  }
}

问题根源

Angular的provideAppInitializer虽支持异步初始化函数(返回Promise),但组件构造函数是同步执行的。如果数据库初始化的异步操作还未完成,组件就已经尝试获取数据库实例,就会触发该错误。即使依赖App Initializer等待初始化完成,某些场景下(比如路由预加载、组件提前实例化)仍可能出现组件先于数据库初始化完成的情况。

解决方案

方案1:让数据库服务提供异步获取实例的方法

修改DatabaseService,将getDatabase改为异步方法,确保组件只有在数据库初始化完成后才能获取实例:

import { Injectable } from '@angular/core';
import { createRxDatabase, RxDatabase } from 'rxdb';
import { ItemCollection, itemSchema } from '../items/items.schema';
import { getRxStorageMemory } from 'rxdb/plugins/storage-memory';

type MyDatabaseCollections = {
  items: ItemCollection;
};
type MyDatabase = RxDatabase<MyDatabaseCollections>;

@Injectable({
  providedIn: 'root',
})
export class DatabaseService {
  private static databasePromise: Promise<MyDatabase> | null = null;

  constructor() {}

  async initDatabase(): Promise<void> {
    if (!DatabaseService.databasePromise) {
      DatabaseService.databasePromise = (async () => {
        const db = await createRxDatabase<MyDatabaseCollections>({
          name: 'mydb',
          storage: getRxStorageMemory(),
        });

        await db.addCollections({
          items: {
            schema: itemSchema,
          },
        });

        return db;
      })();
    }
    await DatabaseService.databasePromise;
  }

  async getDatabase(): Promise<MyDatabase> {
    if (!DatabaseService.databasePromise) {
      throw new Error('Database initialization has not been started');
    }
    return DatabaseService.databasePromise;
  }
}

修改ItemsComponent,在ngOnInit中异步获取数据库(避免在构造函数中执行异步操作):

import { Component, OnInit } from '@angular/core';
// 导入其他依赖...

@Component({
  selector: 'app-items',
  imports: [ToastModule],
  templateUrl: './items.component.html',
})
export class ItemsComponent implements OnInit {
  items: ItemType[] = [];

  constructor(
    private toastService: ToastService,
    private databaseService: DatabaseService,
  ) {}

  ngOnInit(): void {
    this.getItems();
  }

  async getItems() {
    try {
      const db = await this.databaseService.getDatabase();
      const items$ = db.items.find().$;

      items$.subscribe((docs) => {
        console.log(docs);
        this.items = docs;
      });
    } catch (err) {
      this.toastService.show('Failed to load items', { status: 'error' });
    }
  }
}

方案2:用Observable跟踪数据库就绪状态

通过BehaviorSubject监听数据库初始化状态,组件订阅该状态后再执行数据操作:

修改DatabaseService:

import { Injectable, BehaviorSubject, Observable, filter } from '@angular/core';
import { createRxDatabase, RxDatabase } from 'rxdb';
import { ItemCollection, itemSchema } from '../items/items.schema';
import { getRxStorageMemory } from 'rxdb/plugins/storage-memory';

type MyDatabaseCollections = {
  items: ItemCollection;
};
type MyDatabase = RxDatabase<MyDatabaseCollections>;

@Injectable({
  providedIn: 'root',
})
export class DatabaseService {
  private databaseSubject = new BehaviorSubject<MyDatabase | null>(null);
  database$: Observable<MyDatabase> = this.databaseSubject.asObservable().pipe(
    filter(db => db !== null)
  ) as Observable<MyDatabase>;

  constructor() {}

  async initDatabase(): Promise<void> {
    if (!this.databaseSubject.value) {
      const db = await createRxDatabase<MyDatabaseCollections>({
        name: 'mydb',
        storage: getRxStorageMemory(),
      });

      await db.addCollections({
        items: {
          schema: itemSchema,
        },
      });

      this.databaseSubject.next(db);
    }
  }
}

修改ItemsComponent:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
// 导入其他依赖...

@Component({
  selector: 'app-items',
  imports: [ToastModule],
  templateUrl: './items.component.html',
})
export class ItemsComponent implements OnInit, OnDestroy {
  items: ItemType[] = [];
  private subscriptions = new Subscription();

  constructor(
    private toastService: ToastService,
    private databaseService: DatabaseService,
  ) {}

  ngOnInit(): void {
    const dbSubscription = this.databaseService.database$.subscribe(db => {
      const itemsSubscription = db.items.find().$.subscribe((docs) => {
        console.log(docs);
        this.items = docs;
      });
      this.subscriptions.add(itemsSubscription);
    });
    this.subscriptions.add(dbSubscription);
  }

  ngOnDestroy(): void {
    this.subscriptions.unsubscribe();
  }
}

额外检查

确保app.config.ts中的provideAppInitializer正确返回Promise,Angular会等待该Promise完成后再引导应用:

providers: [
  DatabaseService,
  provideAppInitializer(async () => {
    const dbService = inject(DatabaseService);
    await dbService.initDatabase();
  })
],

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:01:02