【源码学习】第14期 | 如何持久化存储数据?推荐你试试configstore!
- 本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
- 第10期 | configstore 存储
前言
configstore
是一个轻量级的键值对存储方案,可以将内容保存在json文件中,官方宣称是轻松地加载和保存配置,而无需考虑位置和方式,关键源码只有109行,知其然方可知其所以然,今天来分析一下configstore
的实现。
收获清单
- 源码调试
- configstore应用
- nodejs如何自动写入文件等
环境准备
下载源码
git clone https://github.com/yeoman/configstore
cd configstore
pnpm install
使用方法看 readme
package.json开启调试
源码一般可以在package.json看到入口文件,先找到入口文件index.js
打好断点,再点击调试脚本
开启调试,也可以node index.js执行调试
调试截图
源码分析
源码一共有108行,按照源码结构我们主要拆成三大部分进行分析
引入依赖
遇到不懂的包推荐 npm 大法:
// 路径模块
import path from 'path';
// os模块,提供与操作系统相关的实用工具方法和属性
import os from 'os';
// fs模块的替代
import fs from 'graceful-fs';
// linux系统获取XDG基本目录路径
import {xdgConfig} from 'xdg-basedir';
// s.writeFile的扩展,以自动和异步的方式写入文件
import writeFileAtomic from 'write-file-atomic';
// 使用点路径从嵌套对象中获取、设置或删除属性
import dotProp from 'dot-prop';
// 生成唯一的随机字符串
import uniqueString from 'unique-string';
通用变量
// xdgConfig XDG基本目录路径
// os.tmpdir()方法是os模块的内置应用程序编程接口,用于获取操作系统临时文件的默认目录路径
const configDirectory = xdgConfig || path.join(os.tmpdir(), uniqueString());
// 错误信息
const permissionError = 'You don\'t have access to this file.';
// 创建目录选项;Oo开头代表八进制
const mkdirOptions = {mode: 0o0700, recursive: true};
// 写入文件选项
const writeFileOptions = {mode: 0o0600};
调试后值如下图:
Configstore 类实现
-
构造器
// 主要是初始化变量
constructor(id, defaults, options = {}) {
const pathPrefix = options.globalConfigPath ?
path.join(id, 'config.json') :
path.join('configstore', `${id}.json`);
// 定义配置路径
this._path = options.configPath || path.join(configDirectory, pathPrefix);
if (defaults) {
// 所有配置
this.all = {
...defaults,
...this.all
};
}
}
-
all
// all取值
get all() {
try {
// 读取配置文件
return JSON.parse(fs.readFileSync(this._path, 'utf8'));
} catch (error) {
// Create directory if it doesn't exist
if (error.code === 'ENOENT') {
return {};
}
// Improve the message of permission errors
if (error.code === 'EACCES') {
error.message = `${error.message}\n${permissionError}\n`;
}
// Empty the file if it encounters invalid JSON
if (error.name === 'SyntaxError') {
writeFileAtomic.sync(this._path, '', writeFileOptions);
return {};
}
throw error;
}
}
// 设置 all
set all(value) {
try {
// Make sure the folder exists as it could have been deleted in the meantime
// 创建目录
fs.mkdirSync(path.dirname(this._path), mkdirOptions);
// 写入内容
writeFileAtomic.sync(this._path, JSON.stringify(value, undefined, '\t'), writeFileOptions);
} catch (error) {
// Improve the message of permission errors
if (error.code === 'EACCES') {
error.message = `${error.message}\n${permissionError}\n`;
}
throw error;
}
}
-
size
get size() {
// Object.keys返回配置的数量
return Object.keys(this.all || {}).length;
}
-
get
get(key) {
// 根据键获取配置值
return dotProp.get(this.all, key);
}
-
set
set(key, value) {
const config = this.all;
// 只有一个参数直接遍历set值
if (arguments.length === 1) {
for (const k of Object.keys(key)) {
dotProp.set(config, k, key[k]);
}
} else {
// 把属性、值设置到all上
dotProp.set(config, key, value);
}
// 更新all
this.all = config;
}
-
has 判断是否有属性值
has(key) {
return dotProp.has(this.all, key);
}
-
delete 根据键移除属性
delete(key) {
const config = this.all;
dotProp.delete(config, key);
this.all = config;
}
-
clear 清空全部数据
clear() {
this.all = {};
}
-
path 获取配置文件的路径
get path() {
return this._path;
}
总结
今天调试分析了configstore
,分析了其关键api的实现,新认识了自动写入文件write-file-atomic
和fs模块的替代graceful-fs
这两个包,configstore
是以键值对形式存储的并且会根据你的操作系统和当前用户来决定最佳的文件存储位置,因此在实际项目中可以用于保存持久化的信息。
转载自:https://juejin.cn/post/7154664800461520933