Angular 我是否每次需要呼叫IndexedDB时都会打开连接?

Angular 我是否每次需要呼叫IndexedDB时都会打开连接?,angular,typescript,indexeddb,Angular,Typescript,Indexeddb,我正在开发一个简单的Angular应用程序,我想在IndexedDB中存储一些数据 我有一个初始化私有数据库的服务在其构造函数中: 但是,当我试图在另一个方法调用中使用构造函数初始化的DB时,这个DB从未定义过。我知道这可能与异步调用、回调和承诺有关,但我不知道是什么。。。所以现在我能想到的唯一解决办法就是打电话 window.indexedDB.open("MyTestDatabase", 1); 每次 import {Injectable} from '@angular

我正在开发一个简单的Angular应用程序,我想在IndexedDB中存储一些数据

我有一个初始化私有数据库的服务在其构造函数中: 但是,当我试图在另一个方法调用中使用构造函数初始化的DB时,这个DB从未定义过。我知道这可能与异步调用、回调和承诺有关,但我不知道是什么。。。所以现在我能想到的唯一解决办法就是打电话

window.indexedDB.open("MyTestDatabase", 1);
每次

import {Injectable} from '@angular/core';
import {Directory, Bookmark} from "./models";
import {connectableObservableDescriptor} from "rxjs/internal/observable/ConnectableObservable";

@Injectable({
    providedIn: 'root'
})
export class BookmarksService {

    private db: IDBDatabase;
    private directoriesStoreName = "directoreis";
    private bookmarksStoreName = "bookmakrs";
    constructor() {
        console.log("Calling Bookmarks Service Constructor .... ");
        if (!window.indexedDB) {
            console.log("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
           
        }
        let openDBRequest: IDBOpenDBRequest = window.indexedDB.open("MyTestDatabase", 1);
        console.log("Let's see if the DB will open .. ")

        /**
         * The only place where a data can be defined is onupgradeneeded callback !
         * @param event
         */
        openDBRequest.onupgradeneeded = (event: any) => {
            console.log("onupgradeneeded fired");
            this.db = event.target.result; 
        };

        openDBRequest.onsuccess = (event: any) => {
            console.log("seems that db is opened ! ");
            console.log(event);
            this.db = event.target.result;
            this.db.onerror = x => {
                console.log("An error occurred while working with DB! ");
            }
        };

        openDBRequest.onerror = event => {
            console.log("can't open IndexedDB");
            console.log(event);
        }


getAllChildDirs(parentId: number): Directory[] {

    if (this.db) { // this is NEVER defined, why ?! 
        var os = this.db.transaction(this.directoriesStoreName).objectStore(this.directoriesStoreName);
        var request = os.index("parent_id");
        var dirs: Directory[] = [];
        request.openCursor(IDBKeyRange.only(parentId)).onsuccess = (event: any) => {
            var cursor = event.target.result;
            if (cursor) {
                // cursor.key is a name, like "Bill", and cursor.value is the whole object.
                console.log("Name: " + cursor.key + ", SSN: " + cursor.value);
                dirs.push(cursor.value);
                cursor.continue();
            }
        };
        return dirs;
    }
}
    }
然后我有一个这样的组件:

export class DirectoriesListComponent implements OnInit {


    @Input() bookmarks: Bookmark[];
    @Input() directories: Directory[];
    isCollapsed = false;

    common: CommonService;
    bookmarksService: BookmarksService;

    constructor(commons: CommonService, bookmarksService: BookmarksService) {
        this.common = commons;
        this.bookmarksService = bookmarksService;
    }

    ngOnInit(): void {
        this.directories = this.bookmarksService.getAllRootDirs(); // ALWAYS returns empty array ?! becuase the db is never defined ... 
        this.bookmarks = this.bookmarksService.getBookmarks();
        //listens on when button is clicked to collapse the menu !
        this.common.dirsMenuCollapsed.subscribe(val => {
            this.isCollapsed = val
        })
    }
import {Injectable} from '@angular/core';
import {Directory, Bookmark} from "./models";
import {connectableObservableDescriptor} from "rxjs/internal/observable/ConnectableObservable";

@Injectable({
    providedIn: 'root'
})
export class BookmarksService {

  private db: IDBDatabase;
  private directoriesStoreName = "directoreis"
  private bookmarksStoreName = "bookmakrs"
  constructor() {
    console.log("Calling Bookmarks Service Constructor .... ")
    // :refac: you can even call it from the constructor, but won't wait as the constructor can't wait async functions to be completed
    this.initializeDatabase()
  }

  private async getDatabase(): Promise<IDBDatabase> {
    // :refac: Now we create a Promise<IDBDatabase> and wait for it when needed
    return new Promise<IDBDatabase>((resolve, reject) => {
      //
      const openDBRequest: IDBOpenDBRequest = window.indexedDB.open("MyTestDatabase", 1)
      console.log("Let's see if the DB will open .. ")

      /**
      * The only place where a data can be defined is onupgradeneeded callback !
      * @param event
      */
      openDBRequest.onupgradeneeded = (event: any) => {
        console.log("onupgradeneeded fired")
        const db = event.target.result
        resolve(db)
      };

      openDBRequest.onsuccess = (event: any) => {
        console.log("seems that db is opened ! ");
        console.log(event)
        const db = event.target.result
        db.onerror = x => {
          console.log("An error occurred while working with DB! ");
        }
        resolve(db)
      };

      openDBRequest.onerror = event => {
        console.log("can't open IndexedDB");
        console.log(event)
        reject()
      }
    })
  }

  async initializeDatabase(): Promise<void> {
    if (!window.indexedDB) 
      return console.log("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.")
    else if (!this.db)
      this.db = await this.getDatabase()
  }

  async getAllChildDirs(parentId: number): Promise<Directory[]> {
    await this.initializeDatabase()
    if (this.db) {
      const os = this.db.transaction(this.directoriesStoreName).objectStore(this.directoriesStoreName)
      const request = os.index("parent_id")
      const dirs: Directory[] = []
      request.openCursor(IDBKeyRange.only(parentId)).onsuccess = (event: any) => {
        const cursor = event.target.result
        if (cursor) {
          // cursor.key is a name, like "Bill", and cursor.value is the whole object.
          console.log("Name: " + cursor.key + ", SSN: " + cursor.value)
          dirs.push(cursor.value)
          cursor.continue()
        }
      }
      return dirs
    }
  }
}

实际上,问题是您无法控制何时调用onsuces函数,因为它是回调函数,并且会在您无法控制的时间执行

但是,您可以采取一些措施来控制它,请查看:

  • 您承诺打开数据库连接并等待它
大概是这样的:

export class DirectoriesListComponent implements OnInit {


    @Input() bookmarks: Bookmark[];
    @Input() directories: Directory[];
    isCollapsed = false;

    common: CommonService;
    bookmarksService: BookmarksService;

    constructor(commons: CommonService, bookmarksService: BookmarksService) {
        this.common = commons;
        this.bookmarksService = bookmarksService;
    }

    ngOnInit(): void {
        this.directories = this.bookmarksService.getAllRootDirs(); // ALWAYS returns empty array ?! becuase the db is never defined ... 
        this.bookmarks = this.bookmarksService.getBookmarks();
        //listens on when button is clicked to collapse the menu !
        this.common.dirsMenuCollapsed.subscribe(val => {
            this.isCollapsed = val
        })
    }
import {Injectable} from '@angular/core';
import {Directory, Bookmark} from "./models";
import {connectableObservableDescriptor} from "rxjs/internal/observable/ConnectableObservable";

@Injectable({
    providedIn: 'root'
})
export class BookmarksService {

  private db: IDBDatabase;
  private directoriesStoreName = "directoreis"
  private bookmarksStoreName = "bookmakrs"
  constructor() {
    console.log("Calling Bookmarks Service Constructor .... ")
    // :refac: you can even call it from the constructor, but won't wait as the constructor can't wait async functions to be completed
    this.initializeDatabase()
  }

  private async getDatabase(): Promise<IDBDatabase> {
    // :refac: Now we create a Promise<IDBDatabase> and wait for it when needed
    return new Promise<IDBDatabase>((resolve, reject) => {
      //
      const openDBRequest: IDBOpenDBRequest = window.indexedDB.open("MyTestDatabase", 1)
      console.log("Let's see if the DB will open .. ")

      /**
      * The only place where a data can be defined is onupgradeneeded callback !
      * @param event
      */
      openDBRequest.onupgradeneeded = (event: any) => {
        console.log("onupgradeneeded fired")
        const db = event.target.result
        resolve(db)
      };

      openDBRequest.onsuccess = (event: any) => {
        console.log("seems that db is opened ! ");
        console.log(event)
        const db = event.target.result
        db.onerror = x => {
          console.log("An error occurred while working with DB! ");
        }
        resolve(db)
      };

      openDBRequest.onerror = event => {
        console.log("can't open IndexedDB");
        console.log(event)
        reject()
      }
    })
  }

  async initializeDatabase(): Promise<void> {
    if (!window.indexedDB) 
      return console.log("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.")
    else if (!this.db)
      this.db = await this.getDatabase()
  }

  async getAllChildDirs(parentId: number): Promise<Directory[]> {
    await this.initializeDatabase()
    if (this.db) {
      const os = this.db.transaction(this.directoriesStoreName).objectStore(this.directoriesStoreName)
      const request = os.index("parent_id")
      const dirs: Directory[] = []
      request.openCursor(IDBKeyRange.only(parentId)).onsuccess = (event: any) => {
        const cursor = event.target.result
        if (cursor) {
          // cursor.key is a name, like "Bill", and cursor.value is the whole object.
          console.log("Name: " + cursor.key + ", SSN: " + cursor.value)
          dirs.push(cursor.value)
          cursor.continue()
        }
      }
      return dirs
    }
  }
}
从'@angular/core'导入{Injectable};
从“/models”导入{Directory,Bookmark};
从“rxjs/internal/observable/ConnectableObservable”导入{connectableobservedscriptor};
@注射的({
providedIn:'根'
})
导出类书签服务{
私有数据库:IDB数据库;
private directoriesStoreName=“directoreis”
私人书签StoreName=“BookMakers”
构造函数(){
log(“调用书签服务构造函数…”)
//:refac:您甚至可以从构造函数调用它,但不会等待,因为构造函数不能等待异步函数完成
this.initializeDatabase()
}
私有异步getDatabase():承诺{
//:refac:现在我们创建一个承诺,并在需要时等待它
返回新承诺((解决、拒绝)=>{
//
const openDBRequest:IDBOpenDBRequest=window.indexedDB.open(“MyTestDatabase”,1)
log(“让我们看看数据库是否会打开…”
/**
*唯一可以定义数据的地方是OnupGradeRequired回调!
*@param事件
*/
openDBRequest.onupgradeneeded=(事件:any)=>{
console.log(“onupgradeneeded-fired”)
const db=event.target.result
分辨率(db)
};
openDBRequest.onsuccess=(事件:any)=>{
log(“似乎数据库已打开!”);
console.log(事件)
const db=event.target.result
db.onerror=x=>{
log(“使用DB时出错!”);
}
分辨率(db)
};
openDBRequest.onerror=事件=>{
log(“无法打开IndexedDB”);
console.log(事件)
拒绝
}
})
}
异步初始化数据库():Promise{
如果(!window.indexedDB)
return console.log(“您的浏览器不支持IndexedDB的稳定版本。这样或那样的功能将不可用。”)
否则如果(!this.db)
this.db=等待this.getDatabase()
}
异步getAllChildDirs(parentId:number):承诺{
等待此消息。initializeDatabase()
if(this.db){
const os=this.db.transaction(this.directoriesStoreName).objectStore(this.directoriesStoreName)
常量请求=操作系统索引(“父项id”)
常量目录:目录[]=[]
request.openCursor(IDBKeyRange.only(parentId)).onsuccess=(事件:any)=>{
const cursor=event.target.result
如果(光标){
//cursor.key是一个名称,类似于“Bill”,cursor.value是整个对象。
console.log(“名称:“+cursor.key+”,SSN:“+cursor.value”)
直接推送(游标值)
cursor.continue()
}
}
返回目录
}
}
}
当您返回承诺时,您应该在调用时使用wait:

async ngOnInit(): Promise<void> {
  this.directories = await this.bookmarksService.getAllRootDirs();
  this.bookmarks = await this.bookmarksService.getBookmarks();
  //listens on when button is clicked to collapse the menu !
  this.common.dirsMenuCollapsed.subscribe(val => {
    this.isCollapsed = val
  })
}
async ngOnInit():Promise{
this.directories=等待this.bookmarksService.getAllRootDirs();
this.bookmarks=等待this.bookmarksService.getBookmarks();
//单击按钮以折叠菜单时侦听!
this.common.dirsMenuCollapsed.subscribe(val=>{
this.isCollapsed=val
})
}

打开数据库是一项代价高昂的操作,我的背景是Java后端,这就是为什么我要问这样一个问题:P\No,主要是因为您使用的是
providedIn:root
,因此这将为您的服务创建一个单例实例,这是合适的。但这是一个很好的问题