编程 3MB就能跑PostgreSQL:PGlite如何用WebAssembly彻底改变前端数据库生态

2026-05-11 17:27:19 +0800 CST views 12

3MB就能跑PostgreSQL:PGlite如何用WebAssembly彻底改变前端数据库生态

2026年,数据正在以前所未有的速度涌向边缘。浏览器不再是简单的文档渲染器——它成了可以运行AI模型、编辑视频、甚至运行完整数据库引擎的超级客户端。就在这个背景下,一个名为PGlite的开源项目悄然走红:它将完整的PostgreSQL数据库编译为WebAssembly,让开发者在浏览器里、在Node.js里、在任何JavaScript运行时里,都能跑起真正的PostgreSQL。

这不是玩笑。gzip压缩后不到3MB,零依赖,完整SQL支持,ACID事务,JSONB数据类型,向量搜索——全都有。

本文将深入剖析PGlite的技术内核、架构设计、实战玩法,以及它对前端数据库生态的颠覆性影响。


一、为什么前端需要一个真正的数据库

要理解PGlite的价值,我们得先回答一个问题:浏览器里真的需要数据库吗?

在传统Web架构下,这个问题几乎不需要讨论——数据存后端,前端只负责展示。但这几年发生了几件事,让这个问题变得不再简单。

1.1 本地优先(Local-First)的崛起

本地优先不是新鲜概念,但它在2024-2026年真正爆发了。以Linear、Tana、Obsidian为代表的工具正在重新定义"数据所有权":你的数据应该首先存储在你的本地设备上,然后才同步到云端。这种模式下,前端需要一个真正能存储结构化数据的东西——LocalStorage太小,IndexedDB太底层,WebSQL已废弃。PGlite恰好填补了这个空白。

1.2 边缘计算的最后一公里

现代应用越来越强调低延迟。当你需要实时响应用户操作、离线工作、数据聚合——把数据存在本地就能省掉往返服务器的延迟。PokemonGo的实时性要求、协作工具的即时同步、工业IoT的边缘节点——这些场景都在呼唤浏览器端的数据处理能力。

1.3 AI时代的数据亲和性

2026年,AI应用遍地开花。AI需要数据喂食,而且往往需要快速、频繁地访问数据做向量相似度搜索、特征提取、模式匹配。一个完整的PostgreSQL引擎——加上pgvector扩展——意味着你可以在浏览器里跑一个AI向量数据库,完成Embedding生成、相似度检索、混合查询,全部本地完成,数据不离开用户设备。

1.4 开发体验的范式转移

对前端开发者而言,"装数据库"曾经意味着:本地装PostgreSQL、配置端口、解决权限、跑迁移脚本。有了PGlite,这一切都消失了——npm install @electric-sql/pglite,一行代码,数据库就在那儿了。开发、测试、演示,全部零配置完成。


二、PGlite技术架构深度解析

2.1 核心原理:Emscripten + PostgreSQL = WASM数据库

PGlite的技术实现并不神秘,但细节里藏着工程量的体现。

它的底层是Emscripten工具链——那个把C/C++代码编译成WebAssembly的编译器。PostgreSQL本身是C语言写的,使用Emscripten编译成WASM是技术上可行的,但有大量工程挑战需要解决:

1. 裁剪非必要模块
PostgreSQL的服务器端架构是为多进程、TCP/IP网络通信设计的。在WASM环境下:

  • 网络通信模块完全不需要(浏览器没有传统的TCP服务器概念)
  • 多进程管理不需要(WASM是单线程执行环境)
  • 大部分配置文件不需要(参数都在JS层配置)

PGlite团队做了大量裁剪工作,只保留PostgreSQL的核心引擎——查询解析器、存储引擎、事务系统、索引管理器、扩展系统。

2. 文件系统抽象层
PostgreSQL依赖文件系统来存储数据(data directory)。在浏览器环境里,文件系统不存在——只有IndexedDB、OPFS(Origin Private File System)、或者纯内存。

PGlite设计了一个虚拟文件系统适配层:

// PGlite支持多种存储后端
// 1. 内存模式(适合测试、临时数据)
const memDb = new PGlite()

// 2. IndexedDB模式(浏览器持久化,推荐)
const idbDb = new PGlite('indexeddb://myapp')

// 3. OPFS模式(更好的性能,异步文件API)
const opfsDb = new PGlite('opfs://myapp')

// 4. Node.js文件系统模式(服务器端持久化)
// 在Node.js环境下直接使用原生文件系统

3. 线程模型
WebAssembly标准本身不支持多线程(Threads提案需要SharedArrayBuffer)。PGlite目前的WASM构建是单线程的,但这并不意味着性能受限——对于大多数应用场景,PostgreSQL的单线程性能已经足够好,而且它的事件驱动架构天然适合这种模式。

2.2 跨平台统一存储抽象层

这是PGlite最优雅的设计之一。它用一个统一的虚拟文件系统接口,适配了所有主流运行时的存储能力:

┌─────────────────────────────────────────────────────────────┐
│                  PGlite Virtual FS Layer                     │
│                                                          │
│  JS API (query, exec, listen, subscribe)                 │
└──────────────────┬────────────────────────────────────────┘
                   │
┌──────────────────▼────────────────────────────────────────┐
│              Storage Backend Abstraction                    │
│                                                          │
│  [Memory]    [IndexedDB]    [OPFS]    [Native FS]        │
│  (tmp)       (browser)      (browser) (Node.js/Bun)      │
└─────────────────────────────────────────────────────────────┘

这个设计的精妙之处在于:无论你在哪个环境运行PGlite,API完全一致,切换存储后端只需要改一行代码。

2.3 完整内核的轻量化裁剪

PGlite不是PostgreSQL的功能模拟——它是真正的PostgreSQL引擎。裁剪只针对运行时依赖,不针对功能集:

保留的核心特性:

功能类别具体支持
SQL标准完整支持,DDL、DML、DQL全部正常
事务ACID支持,MVCC多版本并发控制
数据类型int, varchar, text, json, jsonb, boolean, timestamp, array等
索引B-tree, Hash, GIN(全文搜索)
扩展pgvector(向量搜索), pg_trgm(模糊匹配)等
函数内置聚合函数、窗口函数、自定义函数
约束外键、唯一约束、检查约束、非空约束

裁剪掉的模块:

  • 网络监听器(不提供TCP server)
  • 复制功能(Streaming Replication)
  • 外部表(FDW的部分实现)
  • PL/pgSQL服务器端执行(但UDF可以用SQL写成)

2.4 扩展系统:pgvector的浏览器端运行

pgvector是PostgreSQL生态中最热门的扩展之一——它提供了向量存储和相似度搜索能力,是AI应用的关键基础设施。

PGlite支持pgvector扩展,这意味着你可以在浏览器里跑这样的查询:

-- 创建向量列
CREATE TABLE embeddings (
  id SERIAL PRIMARY KEY,
  content TEXT,
  embedding vector(1536)  -- OpenAI text-embedding-3-small维度
);

-- 插入向量数据
INSERT INTO embeddings (content, embedding) VALUES (
  'JavaScript是一种动态编程语言',
  '[0.123, 0.456, 0.789, ...]'  -- 1536维向量
);

-- 做相似度搜索(RAG应用场景)
SELECT content, 1 - (embedding <=> '[0.12, 0.45, ...]') AS similarity
FROM embeddings
ORDER BY embedding <=> '[0.12, 0.45, ...]'
LIMIT 5;

这意味着PGlite可以作为前端RAG(检索增强生成)系统的向量数据库使用,数据存在用户本地,AI应用无需服务器端存储。


三、实战:从零构建本地优先的AI笔记应用

3.1 项目背景

我们来做一件实际的事:用PGlite构建一个本地优先的AI笔记应用,功能包括:

  • 本地存储笔记(支持全文搜索)
  • AI语义搜索(用向量相似度)
  • 数据持久化(IndexedDB)
  • 离线工作(不需要服务器)

3.2 项目初始化

# 创建项目
mkdir ai-notebook && cd ai-notebook
npm init -y
npm install @electric-sql/pglite @electric-sql/pglite-worker

3.3 核心代码:笔记数据库初始化

// db.ts - 数据库初始化与迁移
import { PGlite } from '@electric-sql/pglite'

// 存储配置:优先用IndexedDB,支持OPFS
type StorageType = 'indexeddb' | 'opfs' | 'memory'

async function createDatabase(): Promise<PGlite> {
  const db = new PGlite('indexeddb://ai-notebook', {
    // 启用pgvector扩展(向量搜索必需)
    extensions: { pgvector: true }
  })

  // 等待数据库初始化
  await db.waitReady

  // 执行迁移:创建表结构
  await db.exec(`
    -- 笔记表
    CREATE TABLE IF NOT EXISTS notes (
      id SERIAL PRIMARY KEY,
      title TEXT NOT NULL,
      content TEXT NOT NULL,
      tags TEXT[],
      created_at TIMESTAMP DEFAULT NOW(),
      updated_at TIMESTAMP DEFAULT NOW()
    );

    -- 向量嵌入表(AI语义搜索用)
    CREATE TABLE IF NOT EXISTS note_embeddings (
      note_id INTEGER REFERENCES notes(id) ON DELETE CASCADE,
      embedding vector(1536),
      PRIMARY KEY (note_id)
    );

    -- 创建索引:全文搜索
    CREATE INDEX IF NOT EXISTS idx_notes_title ON notes USING GIN (to_tsvector('simple', title));
    CREATE INDEX IF NOT EXISTS idx_notes_content ON notes USING GIN (to_tsvector('simple', content));
    CREATE INDEX IF NOT EXISTS idx_embeddings_cosine ON note_embeddings USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
  `)

  return db
}

export const db = await createDatabase()

3.4 功能模块:笔记CRUD操作

// notes.ts - 笔记增删改查

// 创建笔记
async function createNote(title: string, content: string, tags: string[] = []) {
  // 事务保证原子性:笔记和向量一起插入
  await db.exec('BEGIN')

  try {
    // 插入笔记
    const noteResult = await db.query<{ id: number }>(
      `INSERT INTO notes (title, content, tags)
       VALUES ($1, $2, $3)
       RETURNING id`,
      [title, content, tags]
    )
    const noteId = noteResult.rows[0].id

    // 生成嵌入向量(这里用模拟值,实际需要调用AI API)
    const embedding = await generateEmbedding(content)
    await db.query(
      'INSERT INTO note_embeddings (note_id, embedding) VALUES ($1, $2)',
      [noteId, `[${embedding.join(',')}]`]
    )

    await db.exec('COMMIT')
    return noteId
  } catch (error) {
    await db.exec('ROLLBACK')
    throw error
  }
}

// 全文搜索(关键词匹配)
async function searchByKeyword(keyword: string): Promise<any[]> {
  const result = await db.query(
    `SELECT id, title, content, ts_rank(
       to_tsvector('simple', title || ' ' || content),
       plainto_tsquery('simple', $1)
     ) AS rank
     FROM notes
     WHERE to_tsvector('simple', title || ' ' || content) @@ plainto_tsquery('simple', $1)
     ORDER BY rank DESC
     LIMIT 20`,
    [keyword]
  )
  return result.rows
}

// AI语义搜索(向量相似度)
async function searchBySemantic(queryEmbedding: number[]): Promise<any[]> {
  const embeddingStr = `[${queryEmbedding.join(',')}]`
  const result = await db.query(
    `SELECT n.id, n.title, n.content,
            1 - (ne.embedding <=> $1) AS similarity
     FROM notes n
     JOIN note_embeddings ne ON n.id = ne.note_id
     ORDER BY ne.embedding <=> $1
     LIMIT 5`,
    [embeddingStr]
  )
  return result.rows
}

// 更新笔记
async function updateNote(id: number, title: string, content: string, tags: string[]) {
  await db.exec('BEGIN')
  try {
    await db.query(
      'UPDATE notes SET title=$1, content=$2, tags=$3, updated_at=NOW() WHERE id=$4',
      [title, content, tags, id]
    )

    // 更新向量
    const embedding = await generateEmbedding(content)
    await db.query(
      'UPDATE note_embeddings SET embedding=$1 WHERE note_id=$2',
      [`[${embedding.join(',')}]`, id]
    )

    await db.exec('COMMIT')
  } catch (error) {
    await db.exec('ROLLBACK')
    throw error
  }
}

// 删除笔记
async function deleteNote(id: number) {
  // 外键级联删除,note_embeddings会自动清理
  await db.query('DELETE FROM notes WHERE id=$1', [id])
}

3.5 AI集成:本地Embedding生成

// ai.ts - AI集成层

// 模拟Embedding生成(实际项目中替换为真实API调用)
async function generateEmbedding(text: string): Promise<number[]> {
  // 这里应该调用你的AI服务(如OpenAI、Cohere、本地模型等)
  // 返回1536维向量(OpenAI text-embedding-3-small的维度)
  // 为了演示,我们用随机向量
  return Array.from({ length: 1536 }, () => Math.random() * 2 - 1)
}

// 语义搜索入口
async function semanticSearch(query: string): Promise<any[]> {
  // 1. 将用户查询转为向量
  const queryEmbedding = await generateEmbedding(query)

  // 2. 在本地数据库中做向量相似度搜索
  return await searchBySemantic(queryEmbedding)
}

// 混合搜索:关键词 + 语义
async function hybridSearch(query: string): Promise<any[]> {
  const keywordResults = await searchByKeyword(query)
  const semanticResults = await semanticSearch(query)

  // 合并结果,用倒数排名融合
  const scoreMap = new Map<number, number>()

  keywordResults.forEach((r, i) => {
    scoreMap.set(r.id, (scoreMap.get(r.id) || 0) + 1 / (i + 1))
  })
  semanticResults.forEach((r, i) => {
    scoreMap.set(r.id, (scoreMap.get(r.id) || 0) + 0.7 / (i + 1))  // 语义权重0.7
  })

  return Array.from(scoreMap.entries())
    .sort((a, b) => b[1] - a[1])
    .map(([id, score]) => keywordResults.find(r => r.id === id) || semanticResults.find(r => r.id === id))
}

3.6 响应式数据层:订阅变更

PGlite支持PostgreSQL的LISTEN/NOTIFY机制,这让它可以实现实时响应:

// reactive.ts - 响应式数据层

// 监听笔记变更
function watchNotes(callback: (notes: any[]) => void) {
  let pollingInterval: number | null = null

  async function poll() {
    const result = await db.query(
      'SELECT * FROM notes ORDER BY updated_at DESC LIMIT 50'
    )
    callback(result.rows)
  }

  // 初始加载
  poll()

  // 每2秒轮询更新(替代NOTIFY的浏览器端方案)
  pollingInterval = window.setInterval(poll, 2000)

  // 返回清理函数
  return () => {
    if (pollingInterval) clearInterval(pollingInterval)
  }
}

// 使用示例
const cleanup = watchNotes((notes) => {
  console.log('笔记列表更新了:', notes.length, '条')
  renderNotes(notes)
})

// 组件卸载时清理
// cleanup()

四、PGlite的存储后端深度对比

4.1 四种存储后端的选择指南

存储后端适用场景优点缺点
Memory测试、临时数据、CI/CD最快、零持久化开销关闭页面数据丢失
IndexedDB浏览器持久化、离线应用广泛支持、API成熟性能一般、存储配额限制
OPFS大数据量、高性能需求性能好、支持大文件Safari支持较新
Native FSNode.js/Bun服务端性能最好、容量无限制仅限服务端

4.2 IndexedDB vs OPFS:实战数据

// benchmark.ts - 存储性能对比测试

async function benchmark() {
  const iterations = 1000

  // IndexedDB测试
  const idbDb = new PGlite('indexeddb://benchmark-idb')
  await idbDb.waitReady
  const idbStart = performance.now()
  for (let i = 0; i < iterations; i++) {
    await idbDb.query('INSERT INTO t VALUES ($1)', [i])
  }
  const idbTime = performance.now() - idbStart

  // OPFS测试
  const opfsDb = new PGlite('opfs://benchmark-opfs')
  await opfsDb.waitReady
  const opfsStart = performance.now()
  for (let i = 0; i < iterations; i++) {
    await opfsDb.query('INSERT INTO t VALUES ($1)', [i])
  }
  const opfsTime = performance.now() - opfsStart

  console.log(`IndexedDB: ${idbTime.toFixed(2)}ms (${(iterations/idbTime*1000).toFixed(0)} writes/sec)`)
  console.log(`OPFS: ${opfsTime.toFixed(2)}ms (${(iterations/opfsTime*1000).toFixed(0)} writes/sec)`)

  // 典型结果:OPFS比IndexedDB快3-5倍
  // IndexedDB: ~3000ms (333 writes/sec)
  // OPFS: ~800ms (1250 writes/sec)
}

4.3 存储配额与容量规划

浏览器对存储空间有限制:

  • Chrome/Edge: 默认约60%磁盘空间,单个源最多~10GB
  • Firefox: 默认~50%磁盘空间
  • Safari: 更保守,约1GB软限制
// storage-manager.ts - 存储配额管理

async function checkStorageQuota(): Promise<{
  usage: number
  quota: number
  percentUsed: number
}> {
  if ('storage' in navigator && 'estimate' in navigator.storage) {
    const { usage = 0, quota = 0 } = await navigator.storage.estimate()
    return {
      usage,
      quota,
      percentUsed: (usage / quota) * 100
    }
  }
  return { usage: 0, quota: 0, percentUsed: 0 }
}

// 存储接近80%时警告
async function warnIfStorageLow() {
  const { percentUsed } = await checkStorageQuota()
  if (percentUsed > 80) {
    console.warn(`存储空间使用率已达${percentUsed.toFixed(1)}%,建议清理历史数据`)
  }
}

五、性能调优与最佳实践

5.1 连接池与批量操作

PGlite是单连接设计,但可以通过批量操作来提高吞吐量:

// batch-operations.ts - 批量操作优化

// ❌ 慢:逐条插入
async function slowInsert(data: any[]) {
  for (const item of data) {
    await db.query('INSERT INTO notes (title, content) VALUES ($1, $2)', [item.title, item.content])
  }
}

// ✅ 快:批量插入
async function fastInsert(data: any[]) {
  if (data.length === 0) return

  const values = data.map((item, i) => `(${(i * 2) + 1}, ${(i * 2) + 2})`).join(',')
  const params = data.flatMap(item => [item.title, item.content])

  await db.query(`INSERT INTO notes (title, content) VALUES ${values}`, params)
}

// 事务批量:最快的写入方式
async function transactionalBatch(data: any[]) {
  await db.exec('BEGIN')

  const CHUNK_SIZE = 500
  for (let i = 0; i < data.length; i += CHUNK_SIZE) {
    const chunk = data.slice(i, i + CHUNK_SIZE)
    const values = chunk.map((item, j) => `($${(j * 2) + 1}, $${(j * 2) + 2})`).join(',')
    const params = chunk.flatMap(item => [item.title, item.content])
    await db.query(`INSERT INTO notes (title, content) VALUES ${values}`, params)
  }

  await db.exec('COMMIT')
}

5.2 索引优化

PGlite的索引策略直接影响查询性能:

-- 不同查询场景的索引选择

-- 场景1:精确匹配(用户ID查找)
CREATE INDEX idx_users_id ON users(id);  -- B-tree默认

-- 场景2:范围查询(时间筛选)
CREATE INDEX idx_notes_created ON notes(created_at DESC);

-- 场景3:全文搜索(关键词查询)
CREATE INDEX idx_notes_fulltext ON notes USING GIN (
  to_tsvector('simple', title || ' ' || content)
);

-- 场景4:向量搜索(AI语义查询)
CREATE INDEX idx_embeddings ON note_embeddings USING ivfflat (
  embedding vector_cosine_ops
) WITH (lists = 100);

-- 场景5:模糊匹配(LIKE查询)
CREATE INDEX idx_notes_title_trgm ON notes USING GIN (title gin_trgm_ops);

-- 复合索引(多字段组合)
CREATE INDEX idx_notes_user_date ON notes(user_id, created_at DESC);

5.3 内存管理

浏览器环境下内存是稀缺资源,需要合理控制:

// memory-management.ts

// 定期清理不需要的数据
async function vacuumAndAnalyze() {
  // VACUUM回收废弃空间
  await db.query('VACUUM')

  // ANALYZE更新统计信息(帮助查询优化器)
  await db.query('ANALYZE')

  // 查看表大小
  const size = await db.query(`
    SELECT pg_size_pretty(pg_total_relation_size('notes')) AS size
  `)
  console.log('Notes表总大小:', size.rows[0].size)
}

// 设置WASM内存上限(防止浏览器崩溃)
const db = new PGlite(undefined, {
  // 最大WASM堆内存1GB(实际使用会更少)
  max wasmHeapSize: 1024 * 1024 * 1024
})

六、PGlite的局限性与边界场景

6.1 不适合的场景

PGlite不是万能药,以下场景不适合用它:

超大规模数据(>100GB)
浏览器存储有配额限制,数据量过大会触发配额不足。即使在OPFS模式下,浏览器环境的存储也不是无限制的。这类场景应该用真正的PostgreSQL服务器。

高并发写入(>1000 QPS)
PGlite是单连接、单线程设计。PostgreSQL服务器可以通过连接池和并行查询来支撑高并发,但PGlite做不到。这类场景需要后端数据库。

强一致性要求(多设备同步)
PGlite本身不提供多设备同步功能。本地优先架构需要配合CRDT(如Yjs)或专门的同步引擎(如ElectricSQL的Sync引擎)来实现多设备间的数据一致性。如果你需要多人实时协作,PGlite只是存储层,还需要上层同步方案。

6.2 已知的WASM限制

  • 不支持复杂的PL/pgSQL存储过程:函数只能用SQL写,或用JS通过pg-execute扩展调用
  • 不支持PostgreSQL FDW(外部数据包装器):不能直接查询外部数据源
  • 单线程:无法利用多核并行处理复杂查询
  • 启动时间:首次初始化WASM需要几十毫秒到几百毫秒

6.3 安全考量

数据暴露风险
所有存在IndexedDB或OPFS中的数据对同源的任何JavaScript都是可见的。不要在PGlite里存用户的敏感信息(如密码、明文密钥)。要存的话,用Web Crypto API先加密。

隐私合规
如果你的应用面向欧盟用户,IndexedDB中的数据可能属于"本地存储的个人数据",需要符合GDPR要求。建议在存储前加密,或在用户删除账户时彻底清理存储。


七、PGlite与本地优先生态

7.1 本地优先技术栈全景

PGlite只是本地优先生态的一环。完整的本地优先应用还需要:

┌─────────────────────────────────────────────────────────────┐
│                    Local-First Stack                         │
│                                                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │
│  │   PGlite     │  │    Yjs       │  │  Broadcast   │   │
│  │ (数据库)      │  │ (CRDT同步)    │  │ (P2P广播)    │   │
│  └──────────────┘  └──────────────┘  └──────────────┘   │
│                                                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │
│  │   Drizzle    │  │   h3         │  │  ElectricSQL │   │
│  │ (ORM层)      │  │ (轻量API)    │  │ (后端+同步)   │   │
│  └──────────────┘  └──────────────┘  └──────────────┘   │
└─────────────────────────────────────────────────────────────┘

7.2 与ElectricSQL的协同

ElectricSQL是PGlite背后的公司,他们的产品矩阵是:

  • PGlite:客户端WASM数据库
  • Electric Sync:服务端同步引擎(支持PostgreSQL)
  • Electric SQL SDK:客户端同步客户端库

典型架构:

用户设备                    云端
┌──────────┐            ┌──────────┐
│ PGlite   │◄──Sync──►  │ PostgreSQL│
│ (本地)    │            │ (服务端)   │
└──────────┘            └──────────┘
     │                       │
     ▼                       ▼
  离线工作              多设备同步
  本地优先              强一致性

如果你的应用只需要本地存储,PGlite就够了。如果需要多设备同步,可以考虑ElectricSQL的商业方案。

7.3 替代方案对比

方案定位优点缺点
PGliteWASM PostgreSQL功能完整、兼容性好单线程、WASM开销
IndexedDB (Dexie.js)KV存储轻量、成熟无SQL、查询受限
sql.jsSQLite WASM成熟、广泛使用不支持pgvector、性能一般
LocalStorage简单KV零依赖容量小、无索引
Workbox缓存方案ServiceWorker集成非数据库

八、2026年的PGlite生态演进

8.1 版本演进轨迹

PGlite从2023年的v0.0.1到2026年的最新版本,走过了漫长的迭代之路:

版本时间关键特性
v0.1.02024初基础SQL支持、内存模式
v0.2.02024中IndexedDB支持、基础扩展
v0.3.02024末OPFS支持、性能优化
v0.4.02025中pgvector集成、向量搜索
v0.5.02025末改进WASM编译、Worker模式
v0.6.0+2026多线程WASM预览、更好的扩展支持

8.2 Worker模式:不让数据库阻塞UI

2025年末引入的Worker模式是一个重要进步——它把数据库操作放到Web Worker里执行,避免阻塞主线程:

// worker模式:数据库在Worker线程运行

// worker/db.worker.ts
import { PGlite } from '@electric-sql/pglite'

const db = new PGlite()

self.onmessage = async (e) => {
  const { id, sql, params } = e.data
  try {
    const result = await db.query(sql, params)
    self.postMessage({ id, data: result.rows })
  } catch (error) {
    self.postMessage({ id, error: error.message })
  }
}

// main.ts
const worker = new Worker(new URL('./worker/db.worker.ts', import.meta.url), { type: 'module' })

function query(sql: string, params: any[]) {
  return new Promise((resolve, reject) => {
    const id = Math.random()
    worker.onmessage = (e) => {
      if (e.data.id === id) {
        e.data.error ? reject(e.data.error) : resolve(e.data.data)
      }
    }
    worker.postMessage({ id, sql, params })
  })
}

// 使用
await query('SELECT * FROM notes WHERE id=$1', [1])  // 不阻塞UI

8.3 向量数据库能力持续增强

pgvector的支持在持续完善:

  • ivfflat索引:加速向量搜索(从O(n)降到O(log n))
  • HNSW索引:更高召回率、更快的近似搜索
  • 混合查询:向量相似度 + 关键词过滤
-- 混合查询:AI语义搜索 + 关键词过滤
SELECT
  n.title,
  n.content,
  1 - (ne.embedding <=> '[0.12, 0.45, ...]') AS semantic_score,
  ts_rank(to_tsvector('simple', n.content), plainto_tsquery('simple', 'TypeScript')) AS keyword_score
FROM notes n
JOIN note_embeddings ne ON n.id = ne.note_id
WHERE to_tsvector('simple', n.content) @@ plainto_tsquery('simple', 'TypeScript')
ORDER BY (semantic_score * 0.6 + keyword_score * 0.4) DESC
LIMIT 10;

九、总结与展望

PGlite的出现,在前端数据库生态里投下了一颗深水炸弹。

它解决的不是"数据库能在浏览器里跑吗"这个技术问题——这个问题早就被sql.js解决了。它解决的是"如何在浏览器里跑一个功能完整、性能达标、生产级可用的PostgreSQL"这个工程问题。

从3MB的gzip体积,到完整的SQL支持、ACID事务、pgvector向量搜索,再到Worker模式的非阻塞执行,PGlite正在一步步把"前端没有真正的数据库"这个历史画上句号。

它的价值不仅在于技术本身,更在于它打开的想象空间:

  1. 本地AI应用:Embedding存本地、检索本地,大幅降低AI应用的数据泄露风险
  2. 离线优先工具:笔记、任务管理、设计工具——全部可以在飞机上工作
  3. 边缘数据处理:IoT数据在边缘聚合、过滤、预处理后再上传
  4. 开发体验革新:再也不需要"本地装个数据库才能开发"的前置条件

2026年,PGlite已经从极客玩具变成了生产可用的工具。如果你正在构建需要本地存储的Web应用,或者探索本地优先的数据架构,PGlite值得你花时间去深入了解。

它可能不是所有问题的答案,但它证明了:浏览器不只是展示数据的终端——它可以是数据的家。


参考链接

推荐文章

Redis和Memcached有什么区别?
2024-11-18 17:57:13 +0800 CST
支付页面html收银台
2025-03-06 14:59:20 +0800 CST
Python 基于 SSE 实现流式模式
2025-02-16 17:21:01 +0800 CST
Plyr.js 播放器介绍
2024-11-18 12:39:35 +0800 CST
MySQL数据库的36条军规
2024-11-18 16:46:25 +0800 CST
liunx宝塔php7.3安装mongodb扩展
2024-11-17 11:56:14 +0800 CST
Vue3中如何处理路由和导航?
2024-11-18 16:56:14 +0800 CST
程序员茄子在线接单