[TOC]
## 3.5 本地数据缓存
本地数据缓存是小程序存储在当前设备硬盘上的数据,本地数据缓存有非常多的用途:
* 存储用户在小程序上产生的操作,在用户关闭小程序重新打开时可以恢复之前的状态。
* 缓存一些服务端非实时的数据提高小程序获取数据的速度,在特定的场景下可以提高页面的渲染速度,减少用户的等待时间。
### 3.5.1 读写本地数据缓存
小程序提供了读写本地数据缓存的接口,
`wx.getStorage/wx.getStorageSync`读取本地缓存
`wx.setStorage/wx.setStorageSync`写数据到缓存
其中Sync后缀的接口表示是同步接口,执行完毕之后会立马返回,示例代码和参数说明如下所示。
代码清单4-13 wx.getStorage/wx.getStorageSync读取本地数据缓存
~~~
wx.getStorage({
key: 'key1',
success: function(res) {
// 异步接口在success回调才能拿到返回值
var value1 = res.data
},
fail: function() {
console.log('读取key1发生错误')
}
})
try{
// 同步接口立即返回值
var value2 = wx.getStorageSync('key2')
}catch (e) {
console.log('读取key2发生错误')
}
~~~
:-: 表4-4 wx.getStorage/wx.getStorageSync详细参数
| 参数名 | 类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| key | String | 是 | 本地缓存中指定的 key |
| success | Function | 否 | 异步接口调用成功的回调函数,回调参数格式: {data: key对应的内容} |
| fail | Function | 否 | 异步接口调用失败的回调函数 |
| complete | Function | 否 | 异步接口调用结束的回调函数(调用成功、失败都会执行) |
代码清单4-14 wx.setStorage/wx.setStorageSync写入本地数据缓存
~~~
// 异步接口在success/fail回调才知道写入成功与否
wx.setStorage({
key:"key",
data:"value1"
success: function() {
console.log('写入value1成功')
},
fail: function() {
console.log('写入value1发生错误')
}
})
try{
// 同步接口立即写入
wx.setStorageSync('key', 'value2')
console.log('写入value2成功')
}catch (e) {
console.log('写入value2发生错误')
}
~~~
:-: 表4-5 wx.setStorage/wx.setStorageSync详细参数
| 参数名 | 类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| key | String | 是 | 本地缓存中指定的 key |
| data | Object/String | 是 | 需要存储的内容 |
| success | Function | 否 | 异步接口调用成功的回调函数 |
| fail | Function | 否 | 异步接口调用失败的回调函数 |
| complete | Function | 否 | 异步接口调用结束的回调函数(调用成功、失败都会执行) |
### 3.5.2 缓存限制和隔离
小程序宿主环境会管理不同小程序的数据缓存,不同小程序的本地缓存空间是分开的,每个小程序的缓存空间上限为10MB,如果当前缓存已经达到10MB,再通过wx.setStorage写入缓存会触发fail回调。
小程序的本地缓存不仅仅通过小程序这个维度来隔离空间,考虑到同一个设备可以登录不同微信用户,宿主环境还对不同用户的缓存进行了隔离,避免用户间的数据隐私泄露。
由于本地缓存是存放在当前设备,用户换设备之后无法从另一个设备读取到当前设备数据,因此用户的关键信息不建议只存在本地缓存,应该把数据放到服务器端进行持久化存储。
### 3.5.3 利用本地缓存提前渲染界面
讨论一个需求:我们要实现一个购物商城的小程序,首页是展示一堆商品的列表。一般的实现方法就是在页面onLoad回调之后通过wx.request向服务器发起一个请求去拉取首页的商品列表数据,等待wx.request的success回调之后把数据通过setData渲染到界面上,如下代码所示。
代码清单4-15 page.js拉取商品列表数据展示在界面上
~~~
Page({
onLoad: function() {
var that = this
wx.request({
url: 'https://test.com/getproductlist',
success: function (res) {
if (res.statusCode === 200) {
that.setData({
list: res.data.list
})
}
}
})
}
})
~~~
当用户退出小程序再进来,界面仍然会有白屏现象,因为我们需要等待拉取商品列表的请求回来才能渲染商品列表。当然我们还可以再做一些体验上的优化,例如在发请求前,可能我们会在界面上显示一个Loading提示用户在加载中,但是并没有解决这个延迟渲染的现象,这个时候我们可以利用本地缓存来提前渲染界面。
在拉取商品列表后把列表存在本地缓存里,在onLoad发起请求前,先检查是否有缓存过列表,如果有的话直接渲染界面,然后等到wx.request的success回调之后再覆盖本地缓存重新渲染新的列表,如下代码所示。
代码清单4-16 page.js利用本地缓存提前渲染界面
~~~
Page({
onLoad: function() {
var that = this
var list =wx.getStorageSync("list")
if (list) { // 本地如果有缓存列表,提前渲染
that.setData({
list: list
})
}
wx.request({
url: 'https://test.com/getproductlist',
success: function (res) {
if (res.statusCode === 200) {
list = res.data.list
that.setData({ // 再次渲染列表
list: list
})
wx.setStorageSync("list",list) // 覆盖缓存数据
}
}
})
}
})
~~~
这种做法可以让用户体验你的小程序时感觉加载非常快,但是你还要留意这个做法的缺点,如果小程序对渲染的数据实时性要求非常高的话,用户看到一个旧数据的界面会非常困惑。因此一般在对数据实时性/一致性要求不高的页面采用这个方法来做提前渲染,用以优化小程序体验。
### 3.5.4 缓存用户登录态SessionId
通常用户在没有主动退出登录前,用户的登录态会一直保持一段时间(这段时间由开发者根据自己的业务情况定义,为了安全,这段时间不宜设置太长),就无需用户频繁地输入账号密码。如果我们把SessionId记录在Javascript中某个内存变量,当用户关闭小程序再进来小程序时,之前内存的SessionId已经丢失,此时我们就需要利用本地缓存的能力来持久化存储SessionId。
代码清单4-17 利用本地缓存持久存储用户登录态SessionId
~~~
//page.js
var app = getApp()
Page({
onLoad: function() {
// 调用wx.login获取微信登录凭证
wx.login({
success: function(res) {
// 拿到微信登录凭证之后去自己服务器换取自己的登录凭证
wx.request({
url: 'https://test.com/login',
data: { code: res.code },
success: function(res) {
var data = res.data
// 把 SessionId 和过期时间放在内存中的全局对象和本地缓存里边
app.globalData.sessionId =data.sessionId
wx.setStorageSync('SESSIONID',data.sessionId)
// 假设登录态保持1天
var expiredTime = +new Date() +1*24*60*60*1000
app.globalData.expiredTime =expiredTime
wx.setStorageSync('EXPIREDTIME',expiredTime)
}
})
}
})
}
})
~~~
在重新打开小程序的时候,我们把上一次存储的SessionId内容取出来,恢复到内存。
代码清单4-18 利用本地缓存恢复用户登录态SessionId
~~~
//app.js
App({
onLaunch: function(options) {
var sessionId =wx.getStorageSync('SESSIONID')
var expiredTime =wx.getStorageSync('EXPIREDTIME')
var now = +new Date()
if (now - expiredTime <=1*24*60*60*1000) {
this.globalData.sessionId = sessionId
this.globalData.expiredTime = expiredTime
}
},
globalData: {
sessionId: null,
expiredTime: 0
}
})
~~~
- 微信
- 小程序
- 1. 代码组成
- 1.1 JSON配置--'*.json'文件
- 1.2 WXML模板--'*.wxml'文件
- 1.3 WXSS样式--'*.wxss'文件
- 1.4 JavaScript脚本--'*.js'文件
- 2. 客户端运行
- 2.1 逻辑层和渲染层
- 2.1.1 逻辑层--App Service
- 2.1.2 渲染层/视图层--View
- 2.1.3 通信模型
- 2.1.4 数据驱动
- 2.1.5 双线程下的界面渲染
- 2.2 程序与页面
- 2.3 组件
- 2.4 API
- 2.5 事件
- 2.6 兼容
- 3. 应用设计
- 3.1 Flex布局
- 3.2 界面常见的交互反馈
- 3.3 发起HTTPS网络通信--wx.request
- 3.4 微信登录
- 3.5 本地数据缓存
- 3.6 设备能力
- 4. 小程序的协同工作和发布
- 4.1 协同工作
- 4.2 用户体验审视
- 4.3 发布
- 4.4 运营
- 5. 底层框架
- 5.1 双线程模型
- 5.2 组件系统--Exparser框架
- 5.3 原生组件
- 5.4 小程序与客户端通信原理
- 6. 运行和性能优化
- 6.1 启动--代码加载
- 6.2 页面准备
- 6.3 数据通信
- 6.4 视图层渲染
- 6.5 原生组件通信
- 7. 小程序基础库的更新迭代
- 8. 微信开发者工具
- 腾讯云支持
- wafer
- Wafer2 快速开发 Demo - PHP
- WXAPI
- api列表