网站首页 > 技术文章 正文
前言
前段时间在看vue关于proxy的源码,也在头条看了很多文章,之前也写了 一篇关于proxy讨论的文章 。为了更好地理解proxy,打算实际应用到项目中。Web Storage的操作是相对比较繁琐的,正好可以作为应用对象,来提升更好的开发体验。
项目的大体功能已经实现,代码已上传至 github ,也提交了npm包。欢迎大家下载使用,也可进行pr,更好的是点个star。你的认可是我不断前进的动力。
正文
项目名为 proxy-web-storage 。主要是使用proxy代理localStorage和sessionStorage,赋值、取值更加便捷,类型不变,并且支持 null 、 undefined 、 NaN 、 Infinity 等特殊值,还有 Date 、 RegExp 、 Function 等类型的存取。同时可以监听数据变化和设置过期时间。
基本功能——存取、删除
使用方法:
import { local, session } from 'proxy-web-storage';
local.test = 'Hello proxy-web-storage'; // works
delete local.test; // works
复制代码
当然,以上用 web storage 也可以实现。在MDN有指出可以像访问对象一样访问这些值。
localStorage.colorSetting = '#a4509b';
localStorage['colorSetting'] = '#a4509b';
delete localStorage.colorSetting;
复制代码
那么,我的实现有什么新的东西吗?是画蛇添足还是画龙点睛?各位看官接着往下看。
类型保持不变
import { local, session } from 'proxy-web-storage';
// number
local.test = 0;
local.test === 0; // true
// boolean
local.test = false;
local.test === false; // true
// undefined
local.test = undefined;
local.test === undefined; // true
// null
local.test = null;
local.test === null; // true
复制代码
正如上所示,你所赋的值是什么类型,访问的也是对应的类型。而 Web Storage 不管是什么类型,获取的必定是字符串。
localStorage.test = false;
localStorage.test // 'false'
复制代码
这会带来一定的麻烦,如果对 localStorage.test 进行判断的话,那么会返回 true ,这跟我们所期待的并不符合。
当然, proxy-web-storage 还支持 Date 、 RegExp 、 function 类型。
import { local } from 'proxy-web-storage';
// Date
local.test = new Date('2000-01-01T00:00:00.000Z');
local.test.getTime() === 946684800000; // true
// RegExp
local.test = /d(b+)d/g;
local.test.test("cdbbdbsbz"); // true
// function
local.test = function() {
return 'Hello proxy-web-storage!';
};
local.test() === 'Hello proxy-web-storage!'; // true
复制代码
如果是用 localStorage 来操作的话,可以正常保存,但是当再次获取来使用的时候,必须对值进行转换。 Date 还好, Date 构造函数支持 dateString 。 RegExp 会比较麻烦,获取到的值是 '/d(b+)d/g' ,需要拿到 pattern 和 flags 才能重新生成 RegExp 类型。而 function 则是借助 eval 重新生成。
不管怎么说, Date 、 RegExp 、 function 这几种类型的重新生成,多多少少需要写点逻辑代码,使用 proxy-web-storage 则可以省去不少烦恼,所以确定不点个star吗?
直接操作数据
从上面的 Date 和 RegExp 的例子,也可以看出 proxy-web-storage 可以对数据直接进行操作。对于 Object 和 Array ,那么更是方便了,像正常数据一样进行操作,无需进行重复的取值、parse、操作、赋值流程。
proxy-web-storage 让代码更加简洁,舍去重复繁琐逻辑,解放你的双手。
import { local } from 'proxy-web-storage';
// Object
local.test = { hello: 'world' };
local.test.hello = 'proxy-web-storage'; // works
// Array
local.test = ['hello'];
local.test.push('proxy-web-storage'); // works
local.test.length // 2
复制代码
监听数据变化
proxy-web-storage 通过 on 、 once 、 off 可以监听数据的变化。
import { local } from 'proxy-web-storage';
local.on('test', function(newVal, oldVal) {
console.log('test', newVal, oldVal);
});
local.on('test.a', function(newVal, oldVal) {
console.log('test.a', newVal, oldVal);
});
local.test = {};
// test {} undefined
local.test.a = 1;
// test.a 1 undefined
复制代码
对于 Object 和 Array 类型的数据,支持二级监听。 obj.a for Object and list[0] for Array 。还实现了 list.length 的监听,具体实现可滑动至下文查看。
对于 off 方法,如果没有传入key,则移除所有监听对象;如果没有传入callback,则移除指定key的所有回调函数;如果传了callback参数,则只移除callback方法。
设置过期时间
proxy-web-storage 通过 setExpires 、 getExpires 、 removeExpires 可以设置指定项的过期时间。
import { local } from 'proxy-web-storage';
local.test = 'hello proxy-web-storage';
local.setExpires('test', Date.now() + 10000);
// after 10's
local.test // undefined
复制代码
setExpires 如果传入的时间值小于当前时间,则直接删除指定项。
问题
- storage.ts 的 createInstrumentations 方法代码冗余:
(['clear', 'key'] as const).forEach(key => {
instrumentations[key] = target[key].bind(target);
});
instrumentations.getItem = function(keyName: string) {
return get(target, keyName, receiver);
};
instrumentations.removeItem = function(keyName: string) {
return deleteProperty(target, keyName);
};
instrumentations.setItem = function(keyName: string, keyValue: any) {
return set(target, keyName, keyValue, receiver);
};
...
复制代码
原意是模仿vue重写Array方法的写法,但是typescript没入门,怎么写都不对,所以请各位老哥指点一下。
- 关于Array.length的监听
vue是通过 ReactiveEffect 和闭包缓存 oldValue 实现Array.length的监听,可以说watch相关的逻辑都是如此,具体原理可在掘金搜索查看。而我并没有实现 ReactiveEffect 系统,想看通过proxy是否可以进行监听,所以实现上相对会比较繁琐。
length变化的几种情况有:
- push 、 pop 、 shift 、 unshift 、 splice
- let list = []; list.length = 5;
- let list = []; list[5] = 5;
其中第二种情况会触发handler的set,可以直接拿到length的变化,所以按照set的正常逻辑可以完成监听。而第三种并不会触发set,但先按下不表。
第一种情是通过重写以上方法,记录方法执行前的length,以及执行后的length。
(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
instrumentations[key] = function (this: unknown[], ...args: unknown[]) {
lengthAltering = true;
const oldLength: number = this.length;
const res = (proxyMap.get(this) as any)[key].apply(this, args)
if(this.length > oldLength) {
selfEmit(this, 'length', this.length, oldLength);
}
lengthAltering = false;
return res
}
});
复制代码
其中有个 lengthAltering 变量,是用来干什么的呢?
这就要结合第三种情况来讨论了。
let list = []; list.push(1, 2); 相当于 list[0] = 1; list[1] = 2; 。也就是说,第一种情况会影响第三种情况的判断,所以加多一个变量辅助。借助这个变量以及 key 是否大于等于 list.length ,来得到第三种情况的变化监听。
let arrayLength: number | undefined;
if(isArray(target) && !lengthAltering) {
arrayLength = target.length;
}
const result = Reflect.set(target, key, value, receiver);
if(isArray(target) && arrayLength !== undefined && Number(key) >= arrayLength) {
selfEmit(target, 'length', target.length, arrayLength);
}
复制代码
以上是关于Array.length的监听实现,脑袋嗡嗡的,极有可能走了弯路。 想请教有没有更简洁的实现?
猜你喜欢
- 2024-09-27 利用Vue中keep-alive,快速实现页面缓存
- 2024-09-27 vue i18n实现语言切换 vue怎么设置中文版本
- 2024-09-27 Node + Express + Mysql: Todo List项目让你成全栈
- 2024-09-27 vue仓库、组件间通信、前后台数据交互、前端储存数据大汇总
- 2024-09-27 多人群聊实现其实很简单:Nodejs+WebSocket+Vue轻松实现Web IM
- 2024-09-27 Todo List:Node+Express 搭建服务端连接Mysql - 第五章(第1节)
- 2024-09-27 推荐一个Vue3搭建的低代码数据可视化开发平台
- 2024-09-27 Vue认知及使用 vue了解
- 2024-09-27 Vue项目中实现用户登录及token验证
- 2024-09-27 vue3+ts项目搭建和封装(下篇) vue2.0 ts
你 发表评论:
欢迎- 最近发表
-
- 在 Spring Boot 项目中使用 activiti
- 开箱即用-activiti流程引擎(active 流程引擎)
- 在springBoot项目中整合使用activiti
- activiti中的网关是干什么的?(activiti包含网关)
- SpringBoot集成工作流Activiti(完整源码和配套文档)
- Activiti工作流介绍及使用(activiti工作流会签)
- SpringBoot集成工作流Activiti(实际项目演示)
- activiti工作流引擎(activiti工作流引擎怎么用)
- 工作流Activiti初体验及在数据库中生成的表
- Activiti工作流浅析(activiti6.0工作流引擎深度解析)
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)