[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列表