使用 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)。
搭配 Origin 私人檔案系統持續性後端使用 SQLite Wasm
從 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()
方法。這個方法會傳回承諾,並解析為 FileSystemSyncAccessHandle
物件,可用於同步讀取及寫入檔案。此方法的同步性質可帶來效能優勢,但因此只能在專用 Web Workers 中使用,用於處理來源私人檔案系統中的檔案,以免主執行緒遭到封鎖。
設定必要的標頭
下載的 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
,而設定這些標頭是其安全性規定的一部分。
如果您使用開發人員工具檢查流量,應該會看到下列資訊:
網路速度測試
SQLite 團隊已對 WebAssembly 實作項目執行一些基準測試,並與已淘汰的 Web SQL 進行比較。這些基準測試顯示,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 Viewer 之類的應用程式檢查資料庫,確保 SQLite Wasm 確實能正常運作。
取得協助及提供意見回饋
SQLite Wasm 是由 SQLite 社群開發及維護。請前往支援論壇搜尋及發布內容,以便取得協助及提供意見回饋。您可以在 SQLite 網站上查看完整的說明文件。