使用 SQLite 處理所有儲存空間需求,以便在網路上順暢運作。
SQLite 是熱門的開放原始碼簡易嵌入式關聯資料庫管理系統。許多開發人員都使用這項服務,以易於使用的結構化方式儲存資料。由於 SQLite 的大小和記憶體需求較低,因此經常用於行動裝置、桌面應用程式和網路瀏覽器中,做為資料庫引擎。
SQLite 的主要特色之一,就是採用無伺服器資料庫,因此不需要另外的伺服器程序即可運作。而是將資料庫儲存在使用者裝置上的單一檔案中,以便輕鬆整合至應用程式。
以 WebAssembly 為基礎的 SQLite
有許多以 WebAssembly (Wasm) 為基礎的非官方 SQLite 版本,可在網路瀏覽器中使用,例如 sql.js。sqlite3 WASM/JS 子專案是第一個與 SQLite 專案正式相關的專案,可製作程式庫的 Wasm 版本,建立支援 SQLite 的一系列可交付成果。這項專案的具體目標包括:
- 繫結低階 sqlite3 API,以便在使用方面盡可能接近 C API。
- 更高層級的物件導向 API,更類似於 sql.js 和 Node.js 樣式實作,可直接呼叫低階 API。這個 API 必須與低階 API 在同一個執行緒中使用。
- 以 worker 為基礎的 API,可透過 worker 訊息與先前的 API 通訊。這個 API 適用於主執行緒,其中較低層級的 API 會安裝在 worker 執行緒中,並透過 worker 訊息與其通訊。
- 這是 Worker API 的承諾式變化版本,可完全隱藏跨執行緒通訊方面的內容。
- 支援使用現有 JavaScript API 的持續性用戶端儲存空間,包括原始私人檔案系統 (OPFS)。
搭配使用 SQLite Wasm 與 Origin 私人檔案系統持續性後端
從 npm 安裝程式庫
使用下列指令,從 npm 安裝 @sqlite.org/sqlite-wasm 套件:
npm install @sqlite.org/sqlite-wasm
Origin 私人檔案系統
Origin 私人檔案系統 (OPFS,File System Access API 的一部分) 增添了特殊介面,可提供高效的資料存取功能。這個新的介面不同於現有介面,提供檔案內容直接且專屬的寫入存取權,與現有介面不同。這項變更可讓您持續讀取未刷新的修改內容,並在專屬 worker 上提供同步變化版本,大幅提升效能,並解除新用途的封鎖。
如您所知,專案的最後目標是支援使用現有 JavaScript API 的持續性用戶端儲存空間,這項目標有嚴格的效能要求,必須將資料儲存在資料庫檔案中。這就是 Origin 私人檔案系統,更具體來說,就是 FileSystemFileHandle
物件的 createSyncAccessHandle()
方法。這個方法會傳回 Promise,該 Promise 會解析為 FileSystemSyncAccessHandle
物件,以便同步讀取及寫入檔案。此方法的同步性質具有效能優勢,但只能在專屬網路工作站中用於來源私人檔案系統中的檔案,因此無法封鎖主執行緒。
設定必要標頭
下載的 SQLite Wasm 封存檔除了其他檔案外,還包含 sqlite3.js
和 sqlite3.wasm
檔案,這些檔案組成 sqlite3 WASM/JS 版本。jswasm
目錄包含核心的 SQLite3 成果,頂層目錄則包含示範和測試應用程式。瀏覽器不會透過 file://
網址提供 Wasm 檔案,因此您使用此方式建構的任何應用程式都需要網路伺服器,且該伺服器在提供檔案時,必須在回應中加入下列標頭:
Cross-Origin-Opener-Policy
設為same-origin
指令,只將瀏覽環境只隔離同一來源文件。跨來源文件不會在相同的瀏覽內容中載入。Cross-Origin-Embedder-Policy
設為require-corp
指示詞,這樣文件就只能載入來自相同來源的資源,或明確標示為可從其他來源載入的資源。
這類標頭的原因是 SQLite Wasm 依附於 SharedArrayBuffer
,而設定這些標頭是其安全性需求的一部分。
如果您使用開發人員工具檢查流量,應該會看到下列資訊:
網路速度測試
相較於已淘汰的 Web SQL,SQLite 團隊已針對 WebAssembly 實作執行一些基準測試。這些基準測試顯示,SQLite Wasm 的速度通常與 Web SQL 相當。有時速度會稍微變慢,有時則會稍微變快。請前往結果頁面查看所有詳細資料。
程式碼範例入門
如先前所述,含有 Origin 私人檔案系統持久性後端的 SQLite Wasm 需要從 worker 情境中執行。好消息是,程式庫會自動處理所有這些事,您可以直接從主執行緒使用它。
import { sqlite3Worker1Promiser } from '@sqlite.org/sqlite-wasm';
(async () => {
try {
console.log('Loading and initializing SQLite3 module...');
const promiser = await new Promise((resolve) => {
const _promiser = sqlite3Worker1Promiser({
onready: () => {
resolve(_promiser);
},
});
});
console.log('Done initializing. Running demo...');
let response;
response = await promiser('config-get', {});
console.log('Running SQLite3 version', response.result.version.libVersion);
response = await promiser('open', {
filename: 'file:worker-promiser.sqlite3?vfs=opfs',
});
const { dbId } = response;
console.log(
'OPFS is available, created persisted database at',
response.result.filename.replace(/^file:(.*?)\?vfs=opfs$/, '$1'),
);
await promiser('exec', { dbId, sql: 'CREATE TABLE IF NOT EXISTS t(a,b)' });
console.log('Creating a table...');
console.log('Insert some data using exec()...');
for (let i = 20; i <= 25; ++i) {
await promiser('exec', {
dbId,
sql: 'INSERT INTO t(a,b) VALUES (?,?)',
bind: [i, i * 2],
});
}
console.log('Query data with exec()');
await promiser('exec', {
dbId,
sql: 'SELECT a FROM t ORDER BY a LIMIT 3',
callback: (result) => {
if (!result.row) {
return;
}
console.log(result.row);
},
});
await promiser('close', { dbId });
} catch (err) {
if (!(err instanceof Error)) {
err = new Error(err.result.message);
}
console.error(err.name, err.message);
}
})();
示範
如要瞭解上述程式碼的實際運作情形,請參閱示範。請務必查看 Glitch 上的原始碼。請注意,下方的嵌入式版本不會使用 OPFS 後端,但在分開的分頁中開啟示範畫面時,會使用 OPFS 後端。
對 Origin 私人檔案系統進行偵錯
如要對 SQLite Wasm 的 Origin 私人檔案系統輸出內容進行偵錯,請使用 OPFS Explorer Chrome 擴充功能。
安裝擴充功能後,請開啟 Chrome 開發人員工具,然後選取「OPFS Explorer」分頁,即可檢查 SQLite Wasm 寫入原始私人檔案系統的內容。
如果您在 DevTools 的 OPFS Explorer 視窗中選取任何檔案,即可將檔案儲存至本機磁碟。接著,您可以使用 SQLite 檢視器這類應用程式來檢查資料庫,確認 SQLite Wasm 實際上可以正常運作。
取得協助及提供意見回饋
SQLite Wasm 是由 SQLite 社群開發及維護。尋求協助及提供意見回饋,方法是在支援論壇中搜尋並張貼問題。您可以在 SQLite 網站上查看完整說明文件。