Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: localStorage in Taro #4

Merged
merged 6 commits into from
Jun 28, 2020
Merged

feat: localStorage in Taro #4

merged 6 commits into from
Jun 28, 2020

Conversation

songkeys
Copy link
Contributor

@songkeys songkeys commented Jun 26, 2020

为 Taro 增加 Storage polyfill。

QUESTION

  • 浏览器中的 localStorage 效果是存储并返回 string,但是小程序中可以存储任意基本类型和 Object。实践中当然后者更友好,但是否应该为了抹平 API 差异,将内容转换成 string 进行存储?或者暴露出配置接口,由开发者自己决定?
  • 这个 API 实现更像是 tarojsx/history,是否要单独拿出来做一个库?

TODO

@cncolder
Copy link
Member

首先感谢 pr 👍

抹平差异可以算是 polyfill 要做的事情, 放在这里是对的. tarojsx/history 并没有实现浏览器的 History API, 当初在 taro rfcs 里讨论过发现小程序和路由功能和浏览器不兼容.

模拟 localStorage 挂载在 window 对象下, 用到 localStorage 的 npm 包就会尝试使用它, 这些第三方库默认 localStorage.getItem 返回字符串, 尝试对返回结果做解析 JSON.parse, 解析失败后假定数据损坏, 使用默认值替换.

如果 API 不一致, 可能会出现意想不到的结果. 从另一个角度讲, 用户在使用的时候, 也是希望和 web 端保持一致的, Typescript 在 dom.d.ts 里也是把 getItem 和 setItem 的值类型定义为 string 的.

所以我们要解决2个问题:

  1. setItem 时要对 value 进行 String(value) 操作, 经过简单的测试这应该是最接近 localStorage.setItem 的方式.
  2. getItem 时, web 端对于不存在的 key 会返回 null, 而 Taro.getStorageSync 会返回空字符串, 要先判断 key 是否存在, 另外如果获取的值不是字符串, 应该 String(value) 后返回, JSON.parse({a:1})JSON.parse([object Object]) 返回的错误信息是不同的. 看起来有些麻烦.

另外 localStorage[key] 这种方式涉及到 Proxy 太麻烦, 暂且不管吧.

@songkeys
Copy link
Contributor Author

songkeys commented Jun 27, 2020

如果获取的值不是字符串, 应该 String(value) 后返回

是不是用 JSON.stringify 更好一些?

可能会有一些 edge case,但考虑第三方库既然选择通过这个 api 去获取某个 key 对应的值,那么这个值应该是它自己存进去的,一般是不会出现这个值是非 "string" 类型的情况的。

*/
key(index: number): string | null {
const { keys } = Taro.getStorageInfoSync()
if (index >= keys.length) return null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

index < 0 时也应该返回 null, 不加限制会返回 undefined.

@cncolder
Copy link
Member

确实是 JSON.stringify 更好些, 这种情况只会发生在数据是通过 Taro.setStorage 写入的, 之后使用 localStorage.getItem 读取.

Copy link
Member

@cncolder cncolder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

非常感谢, 可以合并的时候告诉我一声, 或者去掉 WIP 标记.

@songkeys
Copy link
Contributor Author

songkeys commented Jun 28, 2020

现在还有 sessionStorage 和 StorageEvent 两个 API 没有补全。

sessionStorage 的实现方式和 localStorage 应该一样,唯一区别是它应该在小程序中的表现是关闭之后清除这次存储的所有数据。(因为小程序没有 onClose 之类的钩子,)实现方式可以是自己在小程序的 storage 里维护一个内部的特殊 key 数组,表示这次会话存储的所有数据的 key。下次打开小程序后,读取并逐一删除相应的数据。

StorageEvent 将依赖于 addEventListener。考虑是否可以用 Taro.Events 实现:https://taro-docs.jd.com/taro/docs/apis/about/events 。或许需要先实现一下它?感觉工程量挺大啊……

@cncolder
Copy link
Member

sessionStorage 最简单的实现方式是使用 new Map<string, string>().

优点:

  • API 相似
  • 与小程序生存周期一致, 短暂休眠不丢失, 冷启动从零开始.
  • 性能

缺点:

  • 占用内存

另外容量无限, 即是优点也是缺点.

}
}

export const localStorage = new Storage()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里应该是 new TaroStorage()

@cncolder
Copy link
Member

StorageEvent 感觉可以先放一放, 先问一下 taro 那边对 window.addEventListener 的态度

@songkeys
Copy link
Contributor Author

OK。那这个 PR 就这样了。你再看看,没问题的话就合并吧~谢谢!

@songkeys songkeys changed the title [WIP] feat: localStorage in Taro feat: localStorage in Taro Jun 28, 2020
@cncolder
Copy link
Member

🍻 合并, 然后我加上 e2e 测试.

@cncolder cncolder merged commit 22bb456 into tarojsx:master Jun 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants