前言
在小程序开发中,跨页面传递数据是一个高频场景。wx.setStorageSync 因其同步调用、简单易用的特点,成为许多开发者的首选方案。
然而,越是简单的东西,越容易被"顺手一写"带出问题。本文以一个小程序页面间数据传递的真实场景为线索,剖析 setStorageSync 使用中最容易踩的 4 个坑,并给出可落地的改进方案。
场景还原:页面 A → 页面 B 的数据传递
假设我们有两个页面:
- 表单页(A) :展示表单,用户点击某个字段后跳转到选择页
- 选择页(B) :用户完成选择操作,点击"确定"后返回 A,并将数据带回
在这种场景下,用 setStorageSync 做数据暂存是最直观的思路。
javascript
// 页面 B:存储数据并返回
wx.setStorageSync("tempData", JSON.stringify(formData));
wx.navigateBack();
ini
// 页面 A:读取数据并回显
const raw = wx.getStorageSync("tempData");
const data = JSON.parse(raw);
wx.removeStorageSync("tempData");
// 使用 data 更新页面
看起来合情合理,对吗?但实际上,这段代码里隐藏着至少 3 个隐患。
误区一:画蛇添足的 JSON 双重解析
问题代码
javascript
// 存储时
wx.setStorageSync("tempData", JSON.stringify(formData));
// 读取时
const raw = wx.getStorageSync("tempData"); // raw 已经是对象了!
const data = JSON.parse(raw); // 多余的解析
根本原因
wx.getStorageSync 会自动反序列化存储的值。 小程序的底层存储机制决定了:存入 JSON.stringify 后的字符串,取出时会被自动还原为原始对象。
| 存入的值 | 取出的值 |
|---|---|
{a: 1} |
{a: 1}(对象) |
"{a: 1}"(字符串) |
{a: 1}(对象,自动解析) |
"hello" |
"hello"(字符串) |
所以上面的 raw 早已是对象,再次执行 JSON.parse(raw) 会触发以下问题:
- 如果
raw是对象,JSON.parse会抛出SyntaxError - 如果
raw恰好是null或undefined,同样会报错
正确做法
kotlin
// 直接存对象
wx.setStorageSync("tempData", formData);
// 直接取对象
const data = wx.getStorageSync("tempData");
// 直接使用 data,不需要 JSON.parse
原则 :
setStorageSync天然支持对象存储,无需手动序列化。只有在需要跨端传输或拼接字符串时才考虑JSON.stringify。
误区二:无视存储失败的"裸奔"调用
问题代码
ini
wx.setStorageSync("tempData", formData);
wx.navigateBack();
隐藏的风险
wx.setStorageSync 虽然是同步 API,但它可能会抛出异常:
- 存储空间不足(单个小程序上限约 10MB)
- 数据中包含不可序列化的内容(如循环引用、函数等)
- 用户存储权限被禁用(极端情况)
当异常发生时,navigateBack 不会执行,用户会卡在当前页面,没有任何提示。
正确做法
php
try {
wx.setStorageSync("tempData", formData);
} catch (e) {
wx.showToast({ title: "数据保存失败,请重试", icon: "none" });
return;
}
wx.navigateBack();
原则 :所有同步存储操作都应使用
try-catch包裹,确保异常被捕获并给用户明确反馈。
误区三:只存不删的"垃圾堆积"
问题描述
很多开发者只关注"存"和"取",却忘了"删"。
kotlin
// 页面 A:读取后不删除
const data = wx.getStorageSync("tempData");
// 使用 data...
// 没有执行 removeStorageSync
后果
- 数据污染:用户下次进入页面 A 时,可能读到上一次遗留的缓存数据
- 逻辑混乱 :页面 A 的
onShow中如果同时有加载请求和缓存读取,容易出现竞态条件 - 存储浪费:虽然单条数据不大,但长期累积会影响性能
正确做法
kotlin
const data = wx.getStorageSync("tempData");
if (data) {
// 使用数据
wx.removeStorageSync("tempData"); // 用后即焚
}
原则:临时数据应当遵循"存-取-删"的生命周期,用完即清理。
误区四:硬编码的"幽灵字段"------无效数据污染
这是最隐蔽、也最容易被忽视的问题。
问题现象
选择页(B)的表单数据结构中包含了一些固定值:
arduino
formData: {
province: "甘肃省", // 硬编码
city: "庆阳市", // 硬编码
district: "",
address: "",
}
但表单页(A)只使用了其中三个字段:
ini
// 页面 A 回显时只取了这三个
formData.district = data.district;
formData.address = data.address;
formData.location = data.location;
// province 和 city 被完全忽略
问题本质
- 选择页(B)存储了多余字段,增加了不必要的序列化开销
- 表单页(A)对部分字段视而不见,造成"写了等于没写"的无效存储
- 当业务扩展(如需要回显省份时),这些字段因为从未被更新过,依然是硬编码值
正确做法
方案一:按需存储(推荐)
只存储目标页面真正需要的字段:
kotlin
// 选择页存储时只取必要字段
const payload = {
district: this.data.formData.district,
address: this.data.formData.address,
location: this.data.formData.location,
};
wx.setStorageSync("tempData", payload);
方案二:统一数据契约
如果数据模型复杂,建议在页面间约定统一的字段映射表,确保存储结构和消费结构一致。
原则:存什么、取什么,应该是一一对应的关系。多余字段要么不用,要么就完整使用。
综合改进示例
选择页(B)
kotlin
confirmSelection() {
const { district, address, location } = this.data.formData;
// 1. 校验
if (!district) {
wx.showToast({ title: "请选择地区", icon: "none" });
return;
}
// 2. 按需组装数据
const payload = { district, address, location };
// 3. 安全存储
try {
wx.setStorageSync("tempData", payload);
} catch (e) {
wx.showToast({ title: "保存失败,请重试", icon: "none" });
return;
}
// 4. 返回
wx.navigateBack();
}
表单页(A)
kotlin
onShow() {
const data = wx.getStorageSync("tempData");
if (data) {
// 使用数据
this.setData({
"formData.district": data.district,
"formData.address": data.address,
"formData.location": data.location,
});
// 清理缓存
wx.removeStorageSync("tempData");
}
}
setStorageSync 最佳实践清单
| 规范 | 说明 |
|---|---|
| ✅ 直接存对象 | 无需 JSON.stringify,小程序会自动处理 |
| ✅ 取用即删除 | 临时数据遵循"存-取-删"生命周期 |
| ✅ try-catch 包裹 | 捕获存储异常,避免页面卡死 |
| ✅ 按需存储 | 只存对方需要的字段,减少冗余 |
| ✅ Key 命名规范 | 使用有意义的命名,如 page_temp_data,避免冲突 |
| ❌ 不存敏感信息 | 本地存储可被查看,切勿存密码、token 等 |
| ❌ 不过量存储 | 单条数据控制在 2MB 以内,避免性能问题 |
结语
wx.setStorageSync 是小程序开发中最基础的能力之一。但也正因为它"太容易用了",反而让很多问题被忽略。
本文梳理的四个误区------JSON 双重解析、无异常处理、用完不删、冗余字段------几乎在每个项目中都能找到类似案例。它们的共同点是:单个操作看起来都没问题,但组合在一起,就成了隐形的技术债。
下次在 Code Review 中看到 setStorageSync 时,不妨多问一句:这个地方需要 JSON.stringify 吗?有 try-catch 吗?用完删了吗?