可持久化的本地存储方案的简单实现 – configstore源码解析学习

本文参加了由公众号@若川视野 发起的每周源码共读活动,      点击了解详情一起参与。

这是源码共读的第10期 | configstore 存储

前言

configstore 是一个轻量级的 本地持久化的存储实现,其本质就是对于本地JSON文件的键值对读写,我们无需考虑在何处以及如何去加载它

使用

npm install configstore

import fs from 'node:fs';
import Configstore from 'configstore';

const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));

// Create a Configstore instance.
const config = new Configstore(packageJson.name, {foo: 'bar'});



console.log(config.get('foo'));
//=> 'bar'


config.set('awesome', true);
console.log(config.get('awesome'));
//=> true

// Use dot-notation to access nested properties.
config.set('bar.baz', true);
console.log(config.get('bar'));
//=> {baz: true}

config.delete('awesome');
console.log(config.get('awesome'));
//=> undefined

源码

index.js 整体源码100行出头

初始化和常量

const configDirectory = xdgConfig || path.join(os.tmpdir(), uniqueString());
const permissionError = 'You don\'t have access to this file.';
const mkdirOptions = {mode: 0o0700, recursive: true};
const writeFileOptions = {mode: 0o0600};

xdgConfig 通过 xdg-basedir 获取用户目录下的配置文件路径, path.join(os.tmpdir(), uniqueString()) 获取的是当前用户目录 + 随机字符串的路径

constructor(id, defaults, options = {}) {
		const pathPrefix = options.globalConfigPath ?
			path.join(id, 'config.json') :
			path.join('configstore', `${id}.json`);
                // 如果没有传入options则取 xdgConfig + pathPrefix的拼接目录
                // 比如我本地的在这里 C:\Users\Harexs\.config\configstore
		this._path = options.configPath || path.join(configDirectory, pathPrefix);
                // 默认对象 解构覆盖值
		if (defaults) {
			this.all = { 
				...defaults,
				...this.all
			};
		}
	}

all – get/set

getset 中会对 all 进行访问,所以这里先看 它对应的 getter/setter, 它也是核心的读写属性

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;
		}

读取时,使用graceful-fs 对 本地文件进行访问,将其取出后JSON化, 如果不存在文件或报错根据情况进行处理

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;
		}

触发setter时,创建对应的文件和目录,将对象重新进行覆写

增删改查

dotProp 是一个对象属性操作的包,它允许我们可以用点的形式去操作和访问对象,例如 xxx.xxx

        // 从返回的key获取值
	get(key) {
		return dotProp.get(this.all, key);
	}
        //先得到完整的对象,再根据传递参数的数量进行不同的处理
	set(key, value) {
		const config = this.all;



		if (arguments.length === 1) {
			for (const k of Object.keys(key)) {
				dotProp.set(config, k, key[k]);
			}

		} else {
			dotProp.set(config, key, value);
		}

		this.all = config;
	}


	has(key) {
		return dotProp.has(this.all, key);
	}

	delete(key) {
		const config = this.all;
		dotProp.delete(config, key);
		this.all = config;
	}

	clear() {
		this.all = {};
	}

总结

其最核心就是对于all 的属性访问操作符,通过dotProp 对 属性的夹子(get/set)进行操作, 而其他增删改查则是最基本的对象属性操作,我们可以依靠这个思路 学习写一个不依赖包的轮子, 并尝试使用Proxy来处理, 和使用split 分割的思路来支持xx.xx.xx的操作方式:
harexs-store

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYbBzQWH' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片