2016-11-14 58 views
2

我有一个SPA应用程序,可以对IndexedDB进行多次读/写操作。我应该每次打开一个IDBDatabase还是保持一个实例打开?

打开DB是一个回调的异步操作:

var db; 
var request = window.indexedDB.open("MyDB", 2); 

request.onupgradeneeded = function(event) { 
    // Upgrade to latest version... 
} 

request.onerror = function(event) { 
    // Uh oh... 
} 

request.onsuccess = function(event) { 
    // DB open, now do something 
    db = event.target.result; 
}; 

有两种方法,我可以用这个db实例:

  1. 保持一个db实例页面的生活/温泉?
  2. 致电db.close()当前操作完成后,在下一个操作中打开一个新操作?

这两种模式都有缺陷吗?保持索引数据库是否存在风险/问题?是否有每个open操作的开销/延迟(通过可能的升级)?

回答

3

由于浏览器正在做更多的工作(例如,它可能需要从磁盘读取数据),每次打开连接可能会比较慢。否则,没有真正的缺陷。

既然你提到了升级,那么这两种模式都需要一种不同的方法来用户在另一个标签中打开你的页面,并且它试图用更高的版本打开数据库(因为它从你的服务器下载了更新的代码)。假设旧标签为版本3,新标签为版本4.

在单连接操作的情况下,您会发现open()版本3失败,因为其他标签能够升级到版本4.您可以注意到,开放失败,例如VersionError并通知用户他们需要刷新页面。

在单连接每页的情况下,您在第3版的连接将阻止另一个选项卡。 v4选项卡可响应请求中的"blocked"事件,并让用户知道应关闭较旧的选项卡。或者v3选项卡可以响应连接上的versionupgrade事件,并告诉用户需要关闭它。或两者。

+0

干杯,这正是我需要知道的事情。我想支持多个选项卡,但我也将使用服务工作者,所以我不应该得到一个选项卡获得不同版本(我认为)的场景。更值得关注的是一个选项卡上的连接阻塞另一个选项,我特别想避免这种连接。 – Keith

2

我发现每个操作打开一个连接并不会显着降低性能。我已经运行了一年多的本地Chrome扩展,涉及大量的indexedDB操作,并且已经分析了其性能数百次,并且从未目睹将连接视为瓶颈。这些瓶颈会导致不正确使用索引或存储大块数据块。

基本上,不要将您的决定放在表现上。这在连接方面确实不是问题。

这个问题实际上就是您的代码的人体工程学,您与API的对抗程度如何,您的代码在您看到它时感受到的直观程度,您认为代码的可读性,对新鲜眼睛的欢迎程度(你自己一个月后,或其他人)。处理阻塞问题时,这非常显着,这是间接处理应用程序模式的问题。

我的个人意见是,如果你对编写异步Javascript感到满意,可以使用任何你喜欢的方法。如果您与异步代码纠缠在一起,选择始终打开连接将避免任何问题。我永远不会推荐使用一个全局页面生命周期变量给更新的异步代码。您也在页面的整个生命周期内将变量留在那里。另一方面,如果你发现异常微不足道,并且找到更适合的全局数据库变量,那么一定要使用它。

编辑 - 根据您的意见,我想我会分享我的个人偏好的一些伪代码:

function connect(name, version) { 
    return new Promise((resolve, reject) => { 
    const request = indexedDB.open(name, version); 
    request.onupgradeneeded = onupgradeneeded; 
    request.onsuccess =() => resolve(request.result); 
    request.onerror =() => reject(request.error); 
    request.onblocked =() => console.warn('pending till unblocked'); 
    }); 
} 

async foo(bar) { 
    let conn; 
    try { 
    conn = await connect(DBNAME, DBVERSION); 
    await storeBar(conn, bar); 
    } finally { 
    if(conn) 
     conn.close(); 
    } 
} 

function storeBar(conn, bar) { 
    return new Promise((resolve, reject) => { 
    const tx = conn.transaction('store'); 
    const store = tx.objectStore('store'); 
    const request = store.put(bar); 
    request.onsuccess =() => resolve(request.result); 
    request.onerror =() => reject(request.error); 
    }); 
} 

随着异步/ AWAIT,有没有在你的工作多余conn = await connect()线摩擦力太大功能。

+0

我打算将indexedDB包装在一个基于Promise的API中,该API可以在ES6中与'async'和'await'一起使用,但我认为你的观点 - 对于一个混合了全局变量和异步的模式还有更多的缺陷。 – Keith

相关问题