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