尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

lowdb 实战指南:从 CLI、Express 服务器到浏览器与内存模式的官方示例全解析

lowdb 实战指南:从 CLI、Express 服务器到浏览器与内存模式的官方示例全解析 数据库嵌入式数据库【免费下载链接】lowdbSimple and fast JSON database项目地址https://gitcode.com/gh_mirrors/lo/lowdb点击查看免费下载本篇技术指南围绕 lowdb 官方src/examples/目录下的四个示例展开逐一拆解 CLI 命令行工具、Express 服务器、浏览器 localStorage 以及测试环境内存模式的具体写法并下沉到 预设Presets、核心类 Low/LowSync 与各类 适配器 的源码实现帮助你快速掌握在不同运行环境中以最小代码量落地 lowdb 的完整套路。读完本文你将能独立把 lowdb 嵌入 Node CLI、HTTP 服务、浏览器应用与单元测试四种典型场景。一、官方示例总览一条文档带你看遍四种运行环境lowdb 的官方示例集中放在仓库的 src/examples/ 目录配套的 src/examples/README.md 以一张清单的形式给出了四个示例的定位分别对应四种典型使用场景示例文件应用场景核心适配器/预设cli.ts命令行工具CLIJSONFileSyncPreset同步文件预设server.tsExpress HTTP 服务器JSONFilePreset异步文件预设browser.ts浏览器页面LocalStoragePresetlocalStorage 预设in-memory.ts测试中的快速读写MemorySync内存同步适配器这四个示例恰好覆盖了 lowdb 面向 Node、Electron 与浏览器三大运行环境的核心用法也印证了项目根目录 package.json 中定义的三套子路径导出lowdb/node—— 文件类适配器与 Node 端预设JSONFile、JSONFileSync、TextFile、DataFile等lowdb/browser—— 浏览器端适配器与预设LocalStorage、SessionStorage等lowdb根入口—— 与运行环境无关的核心类与内存适配器Low、LowSync、Memory、MemorySync。本文接下来的每个小节都会先讲示例本身的用法再结合 src/presets 与 src/adapters 中的源码解释其底层原理。二、CLI 示例用同步预设实现零配置命令行工具cli.ts是四个示例中最短的一个完整代码如下见 src/examples/cli.tsimport { JSONFileSyncPreset } from ../presets/node.js type Data { messages: string[] } const message process.argv[2] || const defaultData: Data { messages: [] } const db JSONFileSyncPresetData(file.json, defaultData) db.update(({ messages }) messages.push(message))它的行为很简单从命令行第二个参数process.argv[2]读取一段文本追加到file.json的messages数组中。由于命令行工具通常需要即调即用所以这里选用同步预设JSONFileSyncPreset无需await即可完成读写。2.1 同步预设的源码解析JSONFileSyncPreset定义在 src/presets/node.ts其内部逻辑是export function JSONFileSyncPresetData( filename: PathLike, defaultData: Data, ): LowSyncData { const adapter process.env.NODE_ENV test ? new MemorySyncData() : new JSONFileSyncData(filename) const db new LowSyncData(adapter, defaultData) db.read() return db }这里有一个值得注意的细节当环境变量NODE_ENV等于test时预设会自动改用内存适配器MemorySync而不是真正读写文件。这正是项目 README 中所宣称的测试期间自动切换为快速内存模式Automatically switches to fast in-memory mode during tests的实现位置。也就是说同一个预设代码在测试与生产环境中会表现出不同的持久化行为这为后续第四节的测试思路埋下了伏笔。2.2 同步链路与 update 方法JSONFileSyncPreset返回的是 src/core/Low.ts 中的LowSync实例。示例中调用的db.update(({ messages }) messages.push(message))对应LowSync.update的实现update(fn: (data: T) unknown): void { fn(this.data) this.write() }它的语义是先执行修改函数再自动落盘一次调用完成改数据 写文件两步。如果去掉update等效写法是db.data.messages.push(message) db.write()从源码可以看到LowSync.read()只有在适配器返回了有效数据时才覆盖this.dataread(): void { const data this.adapter.read() if (data) this.data data }因此在 CLI 场景下file.json首次不存在时db.data会保持构造时传入的defaultData即{ messages: [] }随后update写入第一条消息file.json即被创建。你可以用node cli.ts hello连续执行几次观察file.json的内容如何累积。三、服务器示例Express 异步处理与避免阻塞src/examples/server.ts 展示了如何在 Express 服务器中使用 lowdb完整代码为import express from express import asyncHandler from express-async-handler import { JSONFilePreset } from ../presets/node.js const app express() app.use(express.json()) type Post { id: string body: string } type Data { posts: Post[] } const defaultData: Data { posts: [] } const db await JSONFilePresetData(db.json, defaultData) // db.data can be destructured to avoid typing db.data everywhere const { posts } db.data app.get(/posts/:id, (req, res) { const post posts.find((p) p.id req.params.id) res.send(post) }) app.post( /posts, asyncHandler(async (req, res) { const post req.body as Post post.id String(posts.length 1) await db.update(({ posts }) posts.push(post)) res.send(post) }), ) app.listen(3000, () { console.log(listening on port 3000) })3.1 为什么服务器要用异步适配器cli.ts用同步JSONFileSync而server.ts改用异步JSONFile注释里明确说明了取舍见 src/examples/server.ts如果你在开发一个本地服务器且不会遇到并发请求用JSONFileSync会更省事但如果需要避免阻塞请求就应该使用JSONFile。原因在于同步文件 I/O 会阻塞 Node.js 事件循环一旦同时到达多个请求磁盘读写期间的请求都会排队等待而JSONFile走的是异步适配器接口read(): PromiseT | null、write(data): Promisevoid定义见 src/core/Low.ts由Low类驱动不会阻塞事件循环。3.2 异步预设与读取即就绪JSONFilePreset同样定义在 src/presets/node.tsexport async function JSONFilePresetData( filename: PathLike, defaultData: Data, ): PromiseLowData { const adapter process.env.NODE_ENV test ? new MemoryData() : new JSONFileData(filename) const db new LowData(adapter, defaultData) await db.read() return db }注意它返回的是PromiseLowData并且在返回前已经执行过await db.read()。所以示例中await JSONFilePreset(...)之后db.data里就已经装载了db.json的既有内容随后const { posts } db.data的解构可以直接使用。3.3 一个值得留意的更新语义示例的 POST 路由里post.id String(posts.length 1) await db.update(({ posts }) posts.push(post))由于posts是db.data.posts的解构引用posts.push(post)实际修改的就是db.data中的数组update执行完修改函数后自动调用write()把整个db.data序列化写回db.json。这里体现了 lowdb 的核心设计——db.data就是一个普通 JavaScript 对象/数组没有任何魔法no magic你用原生数组方法修改它再通过write()落盘即可。3.4 并发请求的适用前提需要明确lowdb 并不是为高并发写入设计的数据库。仓库根 README.md 的 Limits 一节明确指出lowdb 不支持 Node 的 cluster 模块如果确有并发、多进程写入需求应改用 PostgreSQL、MongoDB 等真正的数据库。因此本示例更适合本地开发、原型搭建或低频写入的场景。四、浏览器示例localStorage 预设实现页面持久化src/examples/browser.ts 是浏览器端最小示例import { LocalStoragePreset } from ../presets/browser.js type Data { messages: string[] } const defaultData: Data { messages: [] } const db LocalStoragePresetData(db, defaultData) db.update(({ messages }) messages.push(foo))这段代码做了三件事以db作为 localStorage 的存储键名创建预设 → 从localStorage读取数据不存在则使用默认值→ 追加一条消息并写回。执行后开发者工具中localStorage的db键下会存有{messages:[foo]}。4.1 浏览器预设源码LocalStoragePreset定义在 src/presets/browser.tsexport function LocalStoragePresetData( key: string, defaultData: Data, ): LowSyncData { const adapter new LocalStorageData(key) const db new LowSyncData(adapter, defaultData) db.read() return db }同目录下还提供了等价的SessionStoragePreset见 src/presets/browser.ts差别仅在底层使用sessionStorage。二者都基于LowSync——因为 Web Storage API 本身是同步的。4.2 LocalStorage 适配器实现适配器实现在 src/adapters/browser/LocalStorage.ts其核心契约满足 src/core/Low.ts 中SyncAdapter的接口read()返回数据或nullwrite(data)写回存储。此外浏览器目录下还有SessionStorage适配器见 src/adapters/browser/SessionStorage.ts用于 session 级的临时持久化。使用前提LocalStorage/SessionStorage只能运行在浏览器环境存在window全局对象且存储值必须是可被JSON.stringify序列化的数据。若要在 Node 中模拟则需配合内存适配器或文件适配器。五、内存示例在测试中替代文件 I/Osrc/examples/in-memory.ts 演示了如何用内存适配器让测试读写零 I/Oimport { LowSync, MemorySync, SyncAdapter } from ../index.js import { JSONFileSync } from ../node.js declare global { namespace NodeJS { interface ProcessEnv { NODE_ENV: test | dev | prod } } } type Data Recordstring, unknown const defaultData: Data {} const adapter: SyncAdapterData process.env.NODE_ENV test ? new MemorySyncData() : new JSONFileSyncData(db.json) const db new LowSyncData(adapter, defaultData) db.read() // Rest of your code...它的思路非常直接根据NODE_ENV环境变量选择适配器——测试环境用MemorySync其他环境用JSONFileSync。由于MemorySync的write()只是把数据存进内存变量见 src/adapters/Memory.ts示例开头的注释明确写道With this adapter, callingdb.write()will do nothing调用write()不会真正落盘因此测试运行既快又不会污染磁盘上的db.json。5.1 与预设内置的测试自动切换呼应这一写法与第二节提到的JSONFilePreset/JSONFileSyncPreset内置逻辑殊途同归——预设已经在内部实现了NODE_ENV test时自动切换为Memory/MemorySync。两者的关系是用预设框架替你做了适配器切换代码更简洁手动选择适配器本例把切换逻辑显式暴露出来便于在测试中注入其他定制适配器或 Mock 数据。5.2 内存适配器源码MemorySync与异步版本Memory均定义在 src/adapters/Memory.tsexport class MemorySyncT implements SyncAdapterT { #data: T | null null read(): T | null { return this.#data || null } write(obj: T): void { this.#data obj } }可以看到write只是把对象引用保存到私有字段#data不涉及任何磁盘、网络开销read在无数据时返回null。这也解释了为什么它被称为测试专用加速器——省去了JSON.stringify序列化与磁盘写入的时间。仓库中 src/adapters/Memory.test.ts 即对该行为进行了单元测试验证。六、串起来看预设、类与适配器的协作关系四个示例虽然面向不同环境但共享同一套由预设 → 类 → 适配器组成的三层架构。以异步链为例调用链为JSONFilePreset └─ new JSONFileData(filename) // 适配器文件读写 JSON 序列化 └─ extends DataFile // 组合 TextFile注入 parse/stringify └─ new LowData(adapter, defaultData) └─ await db.read() // 从适配器读取填充 db.data └─ db.update(fn) / db.write() // 修改数据并写回其中预设层src/presets/node.ts、src/presets/browser.ts提供四种常用组合JSONFilePreset、JSONFileSyncPreset、LocalStoragePreset、SessionStoragePreset内部完成选适配器 建 Low 实例 读取数据三步核心类层src/core/Low.ts提供Low异步与LowSync同步两套实现方法只有read()、write()、update(fn)三个data属性直接存放业务数据适配器层src/adapters按环境分为node/JSONFile、JSONFileSync、TextFile、DataFile、browser/LocalStorage、SessionStorage与通用的Memory/MemorySync。6.1 文件适配器的序列化细节值得补充的是JSONFile的默认格式化行为。查看 src/adapters/node/JSONFile.ts 可以看到它继承自DataFile并注入了序列化参数export class JSONFileT extends DataFileT { constructor(filename: PathLike) { super(filename, { parse: JSON.parse, stringify: (data: T) JSON.stringify(data, null, 2), }) } }其中stringify使用JSON.stringify(data, null, 2)以两空格缩进写出 JSON保证db.json文件可读而 src/adapters/node/DataFile.ts 则把读取文本 → parse与stringify → 写入文本两段逻辑解耦这为换用 YAML、加密、压缩等其他格式提供了扩展点项目 README 的 Adapters 章节 对此有专门介绍。6.2 快速跳转清单如果你想把本文的示例直接改造成自己的项目可参考以下路径四个示例的完整源码src/examples/cli.ts、src/examples/server.ts、src/examples/browser.ts、src/examples/in-memory.ts预设实现src/presets/node.ts、src/presets/browser.ts核心类src/core/Low.ts各适配器src/adapters/node、src/adapters/browser、src/adapters/Memory.ts测试参考src/core/Low.test.ts、src/adapters/Memory.test.ts、src/adapters/node/JSONFile.test.ts。七、边界与注意事项在使用以上示例时有几点需要结合 lowdb 的设计边界加以留意依据来自仓库根 README.md 的 Limits 一节不支持 Node 的 cluster 模块多进程共享同一db.json无法保证写入一致性分布式部署场景请改用真正的数据库。全量序列化开销每次db.write()都会对整个db.data执行JSON.stringify并整体写入。当数据量达到约 10100MB 级别时可能遇到性能问题。官方建议的做法是批量操作、按需落盘尽量集中修改后再调用一次write()而不是每次小改动都写一次。运行环境要求本项目为纯 ESM 包package.json中type: module并声明engines.node 18。浏览器适配器仅在存在window的环境中可用在 Node 中使用时请从lowdb/node子路径导入在浏览器中使用时从lowdb/browser子路径导入。综上src/examples/的四个示例几乎就是 lowdb 最小可用用法的标准答案CLI 用同步预设、服务器用异步预设、浏览器用 Web Storage 预设、测试用内存适配器。理解了这一套对应关系你就能在任何 JavaScript/TypeScript 环境中快速落地一个读即建、改即存的本地 JSON 数据库。赞分享数据库嵌入式数据库【免费下载链接】lowdbSimple and fast JSON database项目地址https://gitcode.com/gh_mirrors/lo/lowdb点击查看免费下载相关推荐WebdriverIO 示例仓库实战指南从云服务、多浏览器到自定义扩展的全套官方示例WebdriverIO 示例仓库实战指南从云服务、多浏览器到自定义扩展的全套官方示例 WebdriverIO 的 examples https://link.测试质量保障Polly.js 官方示例全解析从浏览器拦截到 Node 与 Puppeteer 的七套实战方案Polly.js 官方示例全解析从浏览器拦截到 Node 与 Puppeteer 的七套实战方案 本指南以 docs/examples.md https://测试开发工具Apache Thrift Node.js 示例实战指南从 RPC 服务到浏览器与 HTTP 跨语言调用Apache Thrift Node.js 示例实战指南从 RPC 服务到浏览器与 HTTP 跨语言调用 本篇技术指南以 lib/nodejs/example后端RPC框架序列化代码生成上一篇如何高效获取微信公众号数据开源爬虫工具的完整实践指南下一篇Apate文件伪装工具快速解决文件格式限制的实用方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表