我正在参加「掘金·启航计划」
前情提要
在去年九月份的时候,赋闲在家,为了更好地把自己推销出去,就整了个开源项目——proxy-web-storage,在掘金发过介绍文章——【开源项目】看了vue的源码,我用proxy实现了更强大的storage,也上过阮老师的周刊推荐,目前收获了200+stars。在此,也是感谢阮老师的推荐和各位老哥的支持,也欢迎各位尝试使用和提出建议。
stokado
ok,再次介绍一下 proxy-web-storage,以及此次更新内容。
首先,proxy-web-storage 改名为 stokado(/stəˈkɑːdoʊ/),以下正式用 stokado 称呼。stokado 是 storage 的世界语(一种国际辅助语言)。世界语的理念跟我开源 stokado 的想法是一致的,成为 web storage 的辅助,帮助前端朋友们更好地更方便地去管理 web storage。
1. 语法糖
从之前的名字 proxy-web-storage 可以看出,这个项目主要是借助 proxy
,拦截了对 localStorage
和 sessionStorage
的访问,实现各种类型数据的序列化和反序列化。支持的类型有常见的基本类型,包括 bigint
类型、number
类型的几个特殊值—— NaN
、Infinity
、-Infinity
,还支持Array
类型, Date
类型,RegExp
类型,Function
类型,Set
类型,Map
类型。嗯,不支持 symbol
。
import { local, session } from 'stokado'
// 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 stokado!'
}
local.test() === 'hello stokado!' // true
实现的方式主要是把数据的类型和序列化后的值存进真正的 storage
里,后续的功能也是基于这个数据类型进行开发,类型如下:
interface TargetObject {
type: string
value: string | object
options?: StorageOptions
}
详细也可以看下之前的文章或者点进github查看测试样例了解更多用法,顺便再点个 star 嘿嘿,来都来了。
2. 监听订阅
这个就没啥好说的,熟悉 vue 的同学应该都会手搓一套简单的发布订阅模式吧。不然也可以看看 mitt、tiny-emitter 等开源库的实现方式,基本上大同小异。
有 on,off,以及 once 三个方法,分别是订阅,取消订阅和只触发一次订阅。
import { local } from 'stokado'
local.on('test', (newVal, oldVal) => {
console.log('test', newVal, oldVal)
})
local.on('test.a', (newVal, oldVal) => {
console.log('test.a', newVal, oldVal)
})
local.test = {}
// test {} undefined
local.test.a = 1
// test.a 1 undefined
从上面的例子也可以看到,stokado 对于 Object
和 Array
类型的数据,支持二级监听。obj.a for Object and list[0] for Array, 还有 list.length 的监听。没有对三级以上的数据进行监听处理,如果后续有同学需要这方面的功能,再看看要不要整上吧。或者你有兴趣的话,也欢迎你加入,一起搞事情。
3. 设置过期
stokado 提供了 setExpires,getExpires,removeExpires 三个方法对指定项设置过期时间,获取它的过期时间和移除它的过期设置。
需要注意的是,当传入的时间值小于当前时间,则直接删除指定项。
import { local } from 'stokado'
local.test = 'hello stokado'
local.setExpires('test', Date.now() + 10000)
// within 10's
local.test // 'hello stokado'
// after 10's
local.test // undefined
上面的例子有一个很不友好的地方,设置一个过期时间需要先存储值。我原来构想的是,对已经存在的值进行操作,但如果是新值呢?
这也是此次更新内容之一,setItem 支持 options 配置。
local.setItem('test', 'hello stokado', { expires: Date.now() + 10000 })
4. 一次性取值
这就是标题所说的新增功能点,痛点来自于有时候用 localStorage
作为页面之间跳转的数据传输,在跳转取值后,要把存储值移除掉,如此的重复操作,当然是写进 stokado 省事啦。
只有 setDisposable 一个方法,就是设置指定项只能获取一次值。
import { local } from 'stokado'
local.setItem('test', 'hello stokado', { disposable: true })
// local.test = 'hello stokado'
// local.setDisposable('test')
local.test // 'hello stokado'
local.test // undefined
像 setExpires 一样,setItem 也支持配置,用 disposable 字段。
playwright测试
其实之前是用 jest 写了几个测试样例,主要是语法糖方面,其他功能点没写,是因为 localStorage
在不同页面修改存储,会触发 storageEvent
事件,而 jest 没办法模拟这个事件。所以,如果想对所有功能点加上测试样例的话,就要借助 headless browser。比较有名的工具有 playwright
和 puppeteer
,前者是微软出品,后者是谷歌。从标题可以知道,我选了 playwright。原因如下:
// playwright
test('basic test', async ({ context }) => {
const page1 = await context.newPage();
const page2 = await context.newPage();
await page1.goto('https://juejin.cn/');
await page2.goto('https://juejin.cn/');
await page2.evaluate(() => {
window.addEventListener('storage', (ev) => {
console.log(ev.newValue, ev.oldValue); // hello world! null
})
});
await page1.evaluate(() => {
window.localStorage.setItem('test', 'hello world!');
});
});
// puppeteer
(async () => {
const browser = await puppeteer.launch();
const page1 = await browser.newPage();
const page2 = await browser.newPage();
await page1.goto('https://juejin.cn/');
await page2.goto('https://juejin.cn/');
await page2.evaluate(() => {
window.addEventListener('storage', (ev) => {
console.log(ev.newValue, ev.oldValue); // hello world! undefined
})
});
await page1.evaluate(() => {
window.localStorage.setItem('test', 'hello world!');
});
await browser.close();
})();
其实两者的用法差不多,区别在于它们各自触发 storageEvent 时的 oldValue 不相同,playwright 是 null
,puppeteer 则是 undefined
,而浏览器的表现为 null
。并且 playwright 集成了test相关的断言等函数,还支持Chromium,Firefox,WebKit等不同内核(虽然我只用了Chromium)。
结语
对这次 1.1.0 更新做个总结:
- 正式更名为 stokado,npm也同步更新了。
- setItem 支持 options 配置,目前支持字段有 expires、disposable。
- 新增功能点:一次性取值。
- 增加 playwright 测试样例,补充监听订阅、设置过期、一次性取值等功能以及
localStorage
和sessionStorage
混合使用的相关测试。
其实还想再讲一下关于做开源的感想,但是瞅着这时间快年中总结了,到时候再一起抒发心中所思所想。
最后,感谢各位小伙伴看完,如果有操作 storage 的需求,不妨试试 stokado。不试也没关系,点个 star 再走呗。