小白变大神四:点表示法与前端缓存
《小白变大神,微信小程序云开发快速入门与成本控制实战》系列文章
第四篇:点表示法与前端缓存
前言
在前三篇文章中我们介绍了WxMpCloudBooster
在云数据库操作上的许多实用工具函数。读到这里,你应该已经发现本系列文章的特点,即本系列文章其实是在介绍一种经过我个人实践检验的微信云开发技术方案。你可以基于我给你的方案去快速开发小程序,也可以根据自己的需求把我的工具函数复制到你的项目中,进行思维上的融合。
在这篇文章中,我会介绍关于点表示法、全局变量、前端缓存等方面的工具函数。这些功能大多数小程序都用得上,并且我提供给你的工具函数已经尽可能优化了调用次数的资源消耗,使用这些函数不仅让你提高开发效率,还能让你节约成本。
获取代码库 WxMpCloudBooster
建议你在阅读本系列文章时,自己新建一个项目,然后跟着我的步骤在你的电脑上实践。因此,在本篇文章中,你需要先获取WxMpCloudBooster
库中的代码。
你可以在github代码库:sdjl/WxMpCloudBooster下载,或者使用如下的命令:
# 获取项目
git clone https://github.com/sdjl/WxMpCloudBooster.git
# 切换到本篇文章(文章四)对应的代码库
cd WxMpCloudBooster
git checkout article4
注意:在article4
版本中,我在utils.js
中添加了大量的用得上但没必要花篇幅介绍的函数,你可以自行在代码库中查看。
点表示法a.b.c
用点表示法给对象赋值:putValue
函数
想象一下,如果a
是一个对象,你要给a.b.c.d
赋值为1,你会这样写?
let a // 通过某种方式获得的对象
if (!a.b) {
a.b = {}
}
if (!a.b.c) {
a.b.c = {}
}
a.b.c.d = 1
拜托,大学生才这样写。为此,我们引入了putValue
函数:
utils.putValue(a, 'b.c.d', 1)
putValue
函数会自动创建a.b
、a.b.c
中间对象,它的声明如下:
/**
* 向对象中按照路径赋值,如果路径上的中间对象不存在,则自动创建。
* @param {Object} obj - 目标对象。
* @param {string} key - 属性路径,支持'a.b.c'形式。
* @param {*} value - 要设置的值。
* @param {Object} [options={}] - 可选参数。
* - {boolean} remove_undefined - 如果为true且value为undefined,则删除该属性。
* @throws {Error} 如果obj为null或undefined,或路径不合法(如中间非对象)则抛出异常。
*/
putValue(obj, key, value, {remove_undefined = true} = {}){
// ...
}
使用这个函数有两个地方要注意,一个是如果路径上的中间对象不是对象,会抛出异常。例如a.b=2
,这里b
不是对象,此时会抛出异常。
另一个是如果value
是undefined
,则会删除该属性。例如下面的代码:
utils.putValue(a, 'b.c.d', undefined)
console.log(a) // {b: {c: {}}},putValue会自动创建中间对象,但不会自动删除空对象
但若你真想赋值为undefined
,可设置remove_undefined
参数为false
。
读取对象属性值:pickValue
函数
对应的,如果要获取a.b.c.d
的值,可以使用pickValue
函数:
utils.putValue(a, 'b.c.d', 1)
const value = utils.pickValue(a, 'b.c.d')
console.log(value) // 1
当然你也可以直接使用javascript
的原生语法:
const value = a.b?.c?.d
这两种写法,当中间路径不存在时,均会返回undefined
。
但a.b?.c?.d
这种写法是硬编码,而在实际开发中路径可能是动态的。例如用户要修改一个配置项,这个配置可能是user_config.font.size
也可能是user_config.page.color.background
,如果使用硬编码的方式,可能会写出这样的代码:
if (key === 'font.size') {
user_config.font.size = value
} else if (key === 'page.color.background') {
user_config.page.color.background = value
}
// 更多的if语句...
这样写显然不够优雅,看看putValue
与pickValue
的组合用法。
// 写入用户配置:
utils.putValue(user_config, key, value)
// 读取用户配置
const value = utils.pickValue(user_config, key)
不管key
怎么变,一句话搞定,感觉一下子和大学生拉开差距了是吧?
向数组末尾添加元素:pushValue
函数
在实际开发中,常有向数组末尾添加数据的需求。例如记录用户最近的评论,此时你可以使用pushValue
函数:
const user_data = {} // 用户数据
let comment = {content: '顶'} // 用户的评论
utils.pushValue(user_data, `articles.recent_comments`, comment)
console.log(user_data) // {articles: {recent_comments: [{content: '顶'}]}}
在上面代码中,pushValue
函数先是自动创建了user_data.articles.recent_comments
数组,然后把comment
添加到数组末尾。pushValue
函数的声明如下:
/**
* 将值推入对象指定路径的数组中,若路径或数组不存在则自动创建。
* @param {Object} obj - 目标对象。
* @param {string} key - 数组属性的路径,支持'a.b.c'形式。
* @param {*} value - 要推入的值。
* @throws {Error} 如果路径不是数组,则抛出异常。
*/
pushValue(obj, key, value){
// ...
}
再次调用此函数,数组中就会有两个评论:
comment = {content: '再顶'}
utils.pushValue(user_data, `articles.recent_comments`, comment)
console.log(user_data) // {articles: {recent_comments: [{content: '顶'}, {content: '再顶'}]}}
向对象中添加多个属性:putObj
函数
前面我们使用putValue
函数向obj
对象写入了一个属性值,但如果你要写入很多个(例如100个)属性值,你可能会使用for
循环:
let user_config = {}
let new_config_keys // 100个新的配置项(数组)
let new_config_values // 对应的100个值(数组)
for (let i = 0; i < new_config_keys.length; i++) {
utils.putValue(user_config, new_config_keys[i], new_config_values[i])
}
这样写没问题,但在实战中,你拿到的用户配置往往不是数组的形式,而很可能是一个对象,例如:
let new_config = {
font: {
size: 16,
'family.first': 'Arial',
'family.second': 'sans-serif',
},
'page.color.background': '#fff',
// ...
}
// 你对拿到的配置数据又进一步处理
new_config.update_time = new Date()
这种情况下你可以使用putObj
函数一次性写入多个属性值:
utils.putObj(user_config, new_config)
console.log(user_config)
/* 输出如下:
{
font: {
size: 16,
family: {
first: 'Arial',
second: 'sans-serif'
}
},
page: {
color: {
background: '#fff'
}
},
update_time: '...',
}
*/
注意putObj
会自动处理上面new_config
变量中各种路径的写法。putObj
函数的声明如下:
/**
* 将一个对象的所有属性按路径添加到另一个对象中。
* @param {Object} obj - 目标对象。
* @param {Object} obj_value - 要添加的属性对象,键支持'a.b.c'形式的路径。
* @param {Object} [options={}] - 可选参数。
* - {boolean} remove_undefined - 如果为true且value为undefined,则删除该属性。
* @throws {Error} 如果obj为null或undefined,或路径不合法(如中间非对象)则抛出异常。
*
* 注意
* 若obj_value中出现重复路径,则后者会覆盖前者。
* 如 obj_value = {a: {b: 1}, 'a.b': 2},则结果为 {a: {b: 2}}
*/
putObj(obj, obj_value, { remove_undefined = true} = {}) {
// ...
}
从对象中获取多个属性:pickObj
函数
同样的,我们可以一次性读取多个对象的属性值。例如虽然小程序中的用户配置非常复杂,但当前页面仅关注背景颜色、字体大小等少量配置项,你可以这样使用pickObj
函数:
let user_config // 某个用户的所有配置
// 本页面需要关注的配置
const keys = ['page.color.background', 'font.size', 'font.family']
// 获取当前页面需要的配置
const curr_config = utils.pickObj(user_config, keys)
console.log(curr_config)
/* 输出如下:
{
'page.color.background': '#fff',
'font.size': 16,
'font.family': {
first: 'Arial',
second: 'sans-serif'
}
}
*/
console.log(curr_config.font) // undefined
注意,传给pickObj
函数的第二个参数是一个字符串数组,而不是对象。并且,pickObj
返回的对象中,属性值不是以curr_config.font.size
这样的形式返回,而是返回curr_config['font.size']
。
当然,如果你想要curr_config.font.size
这样的形式,可用putObj
转换一下:
let obj_config = utils.putObj({}, curr_config)
console.log(obj_config.font.size) // 16
点表示法实战演示
为什么要设计这几个函数?为什么要支持config.a.b.c
与config['a.b.c']
两种写法混用?为什么传给putObj
的第二个参数是对象,而传给pickObj
的第二个参数是字符串数组?为什么pickObj
返回的对象属性值不是config.a.b.c
这样的形式,而是config['a.b.c']
?
因为这样设计符合实战需求,一句话解释就是:“这样好用”。
下面我们通过几个案例来演示这些函数在实战中的应用。
在js中设置用户配置
假设用户首次打开小程序,你需要设置用户默认字体大小为16,背景颜色为白色。可以这样写:
let user_config = {}
utils.putValue(user_config, 'font.size', 16)
utils.putValue(user_config, 'page.color.background', '#fff')
提醒:关于如何保存用户配置到数据库,我们会在下一篇文章中介绍。
使用putValue
设置后,你想修改字体大小和背景颜色?可以这样写:
user_config.font.size = 18
user_config.page.color.background = '#000'
在wxml中实现修改用户配置
你可能会在wxml页面中实现多个配置项的修改,并且使用同一个函数来处理。这时你可以这样写:
<button bind:tap="changeConfig" data-key="font.size" value="16" >
<button bind:tap="changeConfig" data-key="page.color.background" value="#fff">
changeConfig(e){
const { user_config } = this.data
const { key, value } = e.currentTarget.dataset
// 从wxml中获得点表示法的key字符串,直接调用putValue函数
utils.putValue(user_config, key, value)
// 修改背景色时顺便改一下字体颜色(两种写法混用)
if (key === 'page.color.background' && value === '#fff') {
user_config.page.color.font_color = '#000'
}
// 记录最近修改时间
user_config.update_time = new Date()
}
在wxml中使用用户配置
要在页面中使用page.color.background
与page.color.font_color
的值,实现根据用户配置显示不同的颜色,可以这样写:
<view style="background-color: {{color.background}}">
<text style="color: {{color.font_color}}">
Hello, WxMpCloudBooster!
</text>
</view>
onLoad(){
const { user_config } = this.data
const color = utils.pickValue(user_config, 'page.color')
this.setData({color})
}
你看,我们传递给pickValue
的key
根据实际需求可长可短。
初始化默认的用户配置
你希望为每个用户设置一个默认的用户配置,并且你想用常规方式写(不使用点表示法)。可以这样:
// 默认配置
const DEFAULT_CONFIG = {
font: {
size: 16,
},
page: {
color: {
background: '#fff',
font_color: '#000'
}
},
// 这里也可以使用点表示法a.b.c,但你不想这样写...
}
App({
initConfig(){
let { user_config } = this.data
utils.putObj(user_config, DEFAULT_CONFIG) // user_config的其他值会被保留
// 保存用户配置...
}
})
注意,上面代码中user_config
可能会有其他没有出现在DEFAULT_CONFIG
中的配置项,这些配置项会被保留。
记录用户最近发表的内容
假如你已经实现了“记录用户最近发布的评论”功能,代码如下:
<button bind:tap="append" data-key="articles.recent_comments" data-prop="comment" >
当用户点击这个按钮时,假设this.data
中已经有一个comment
对象,你可以这样添加评论:
append(e){
const { user_data } = this.data
const { key, prop } = e.currentTarget.dataset
const value = this.data[prop] // prop === "comment"
utils.pushValue(user_data, key, value) // 注意这里用的是push
}
上面这个append
函数会把this.data.comment
对象添加到user_data.articles.recent_comments
数组的末尾。
然后,此时你希望再增加一个按钮,可以把最近的点赞数据this.data.like
添加到user_data.articles.recent_likes
数组的末尾,那么只需一句:
<button bind:tap="append" data-key="articles.recent_likes" data-prop="like" >
完成了,你不需要修改append
函数,只需要给data-key
和data-prop
属性设置不同的值即可。
可见,点表示法很大的目的是为了在wxml
中可以方便地指定路径,并在js
中方便地处理这些路径。
在页面中修改多个配置项
假设你有一个修改用户配置项的页面,wxml
代码如下:
<!-- 注意这里有一个for循环 -->
<view wx:for="{{configs}}">
配置名称:{{item.title}}
当前值:{{item.value}}
输入新值:<input type="text" />
点击修改:<button bind:tap="changeConfig"/>
</view>
上面代码使用了for
循环,configs
变量中有多少个值,就会显示多少个配置项。
为了实现在用户打开页面时显示的是用户的当前值(而不是默认值),你还需要从user_config
中读取当前用户的配置值。
代码样例如下:
// 代码中写死了需要修改的配置项以及默认值
configs = [
{title: '字体大小', key: 'font.size', value: 16},
{title: '背景颜色', key: 'page.color.background', value: '#fff'},
{title: '字体颜色', key: 'page.color.font_color', value: '#000'},
]
// 读取当前用户的配置值
const uc_obj = utils.pickObj(user_config, configs.map(item => item.key))
// 注意,这里的 uc_obj 是 uc_obj['font.size'] 这样的形式,而不是 uc_obj.font.size
// 用户当前值覆盖默认值
configs.forEach(item => {
if (uc_obj[item.key] !== undefined) {
item.value = uc_obj[item.key]
}
})
this.setData({configs}) // 传给wxml页面显示
这样你就实现了修改多个配置项的页面,用户打开页面时显示的是用户当前的配置值。
提问:假设我们坚决不使用点表示法,且要实现上面这些功能,你要如何设计才能如此简单、高效?
让你的函数也支持点表示法
好了,目前我们花了不少篇幅介绍点表示法,这是因为后面我们会介绍更多的工具函数,而这些工具函数都支持点表示法的调用方式。
当你编写自己的工具函数时,你可以调用putValue
、pickValue
、pushValue
、putObj
、pickObj
这5个函数,轻松地让你的工具函数也支持点表示法。如果你不知道如何实现,可以参考utils.js
中其他函数的代码。
全局变量与config
globalData
全局变量
通常,我们需要一个所有页面都可以随时访问的全局变量,我们习惯的把它放在app.js
文件中,并命名为globalData
。
App({
onLaunch: function () {
// ...
},
globalData: {
// 仅当前小程序使用的Behavior(所有小程序都使用的Behavior放到utils.js的PAGE_BEHAVIORS变量中)
behaviors: [],
// 运行期间不会改变的配置
config: {
app_name: 'booster', // 当前小程序项目名称,英文
app_title: '小白变大神', // 当前小程序名称,中文
// ... 更多配置请查看WxMpCloudBooster项目的app.js文件
},
// 小程序当前的运行环境、状态
running: {
is_local: null, // 会在app_init.jd中设置,表示是否运行在微信开发者工具中
is_first_app: true, // 是否是绑定了云环境的第一个项目,通常是admin后台管理项目
is_cloud_ready: false, // 微信云开发的wx.cloud对象是否完成初始化
},
// 可读写缓存
cache: {},
// 页面间传递的临时数据
temp: {},
},
})
globalData
中的这几个属性是约定属性,WxMpCloudBooster
项目需要它们。你可以根据自己的需求添加更多的属性,但注意名称不要和WxMpCloudBooster
项目冲突。这里我们主要关注config
和cache
属性。
globalData.config
配置
通常我们会开发多个小程序项目,而不同的小程序有不同的配置,例如app_name
、app_title
等,这些配置我们放在globalData.config
中。
但要注意,当你修改globalData.config
中的配置时,你需要重新上传代码、等待审核、并发布。因此这些配置项通常是不需要修改的,对于那些在小程序运行期间可能会修改的配置,我们需要保存到数据库中。
这里的app_name
表示项目的英文名称,通常也就是你的小程序代码所在文件夹的名称,且app_name
不会显示给用户看见。
utils.globalData
函数
假如你要在页面中引用globalData
对象,可以这样:
const app = getApp() // getApp是全局函数
const globalData = app.globalData
console.log(globalData.config.app_name)
但我们提供了utils.globalData
函数,你可以这样使用:
const globalData = utils.globalData()
console.log(globalData.config.app_name)
utils.getConfig
函数
像上面那样,先获取globalData
对象再获取config
属性有点麻烦。因此还有utils.getConfig
函数可让代码进一步简洁:
const app_name = utils.getConfig('app_name') // 传入的参数不需要写 config. 前缀
getConfig
函数支持点表示法,因此如果你自己添加了一些其他config
内容,也可以这样获取:
// globalData中的config对象
config: {
app_name: 'booster',
app_title: '小白变大神',
// 假设下面这个page是你自己的配置项
page: {
color: {
background: '#fff',
font_color: '#000'
}
}
}
// 在js中获取
const background_color = utils.getConfig('page.color.background') // 记得这里可长可短
对了,utils.js
中没有setConfig
函数,因为config
的设计是只读的,你不应该在小程序运行期间修改config
属性。
对于那些可能会在小程序运行期间改变的配置,我们会在下一篇文章中介绍如何保存到数据库中,并提供对应的工具函数。
关于running.is_cloud_ready
几乎所有刚接触到云开发的朋友都会遇到这个 “请先调用 wx.cloud.init() 完成初始化后再调用其他云 API” 的异常,因此我觉得有必要提前介绍一下is_cloud_ready
属性。
云开发的wx.cloud
对象需要完成初始化后才能使用,当你在onLoad
函数中调用了wx.cloud
的API
时,wx.cloud
可能还没有完成初始化。running.is_cloud_ready
属性就是用来记录wx.cloud
对象是否完成初始化的。
如果你现在就面临这个问题,你可以先自行了解一下utlis.js
中的cloudReady
函数,我们将在以后的文章中详细介绍。
前端缓存Cache
setCache
函数
微信小程序的API
中并没有前端缓存的相关函数(有Storage,本文后面介绍),但有时候我们需要在前端缓存一些数据,所以我们需要自己实现它。
例如当你读取了一个商品数据时,你希望把这个数据缓存起来,下次打开商品页面时就不用再次读取,从而提高用户体验并减少了调用次数的消耗。
要实现这个功能很简单,只需把要缓存的数据保存全局变量globalData.cache
中即可。为此我们提供了setCache
函数:
/**
* 同步设置内存缓存。若给定的`value`为`undefined`,则删除对应的`key`。
* @param {string} key - 缓存键名,支持使用'a.b.c'的形式访问嵌套属性。
* @param {*} value - 要设置的缓存值。若为`undefined`,则执行删除操作。
*/
setCache (key, value) {
const _ = this
_.putValue(_.globalData().cache, key, value)
},
假设你有一个商品数据,你可以这样缓存:
let product // 从数据库中读取的商品数据
utils.setCache(`products.${product._id}`, product)
// 注意上面这句不能写成`products_${product._id}`,那样不会自动创建中间对象
由于setCache
内部使用了putValue
,而putValue
可以根据点表示法自动创建中间对象,因此上面这行代码最终会把product
保存到globalData.cache.products
对象中,且商品_id
作为products
对象的key
。
setCache
只是把数据保存在内存中,并没有操作数据库,因此setCache
函数是不消耗调用次数的。
getCache
函数
当你需要读取缓存数据时(可以在不同页面中读取),可以使用getCache
函数:
let product_id // 假设你有商品id
const product = utils.getCache(`products.${product_id}`)
getCache
函数代码如下:
/**
* 从内存中获取缓存值。
* @param {string} key - 缓存键名,支持'a.b.c'形式访问嵌套属性。
* @param {Object} options - 可选参数。
* - {any} default_value - 若缓存不存在时的默认值,默认为null。
* @returns {*} 返回找到的缓存值,若未找到则返回`default_value`。
*/
getCache (key, {default_value = null} = {}) {
const _ = this
const v = _.pickValue(_.globalData().cache, key)
return v !== undefined ? v : default_value
},
因为getCache
内部也使用了点表示法,所以如果你只需要从缓存中获取当前产品的价格,可以这样写:
const price = utils.getCache(`products.${product_id}.price`) // 可长可短嘛~
同样getCache
函数也不消耗调用次数。
内存使用的限制
微信并没有规定你可以使用多大的内存空间,这取决于用户手机的内存大小。当你的小程序占用的内存过大时(相对于用户手机内存大小),小程序会收到“内存不足”的警告,如果你不处理,小程序可能会被强退。
这里我给出一个简单的办法,当收到“内存不足”的警告时,清空globalData.cache
对象,可在utils/app_init.js
文件中看到如下代码:
/* 内存不足时清空缓存app.globalData.cache
*/
const initMemoryWarning = (app) => {
wx.onMemoryWarning(() => {
const cache = app.globalData.cache
for (const i in cache) {
delete cache[i]
}
})
}
export default function (app) {
initRunning(app) // 此函数在app_init.js中有定义
initMemoryWarning(app)
}
提醒:前面文章中提到过app_init.js
的使用,你也可以在WxMpCloudBooster
项目的app.js
文件中查看调用案例。
因此,你不能假设使用setCache
后,就一定能从getCache
中读取到数据,你总是需要检查读取值是否为空:
const product = utils.getCache(`products.${product_id}`)
if (utils.isEmpty(product)) {
// 缓存被清空了,需要从数据库中重新读取
}
实战:利用缓存减少调用次数
前面的文章中我们说过,当进入商品列表页面时,我们可以一次性读取多个商品数据,下次进入商品列表页面时就不用再次读取。
下面我们就来演示如何一次性读取100个商品数据并缓存。
进入商品列表页的代码:
// 进入商品列表页面时
onLoad(){
// 尝试从缓存中读取商品数据
let products = utils.getCache('products')
// 检查缓存是否存在
if (utils.isEmpty(products)) {
// 从数据库中读取100个商品数据
products = await utils.allDocs({c: 'products', limit: 100})
// 缓存商品数据
utils.setCache('products', products)
}
// 显示给前端页面
this.setData({products})
}
当用户进入商品详情页时,也可以使用缓存的列表数据,不消耗调用次数:
// 进入商品详情页面时
onLoad(options){
let { product_id } = options // 通过URL传递商品ID
let product = utils.getCache(`products.${product_id}`) // 咦~ 我又变长了~
// 记得检查缓存是否存在...
}
你看,向用户展示100个商品,并且在100个详情页面中跳来跳去,一共消耗了多少次调用次数?答案是1次。
当然,你也可以一次性读取1000条数据甚至更多,只要总数据量不超过5M,详情见上一篇文章的“云数据库的限制”一节。
持久存储Storage
使用setCache
保存数据有一个问题,当小程序被后台销毁时,缓存数据就会丢失(因为数据缓存在小程序的占用内存中)。
如果我们需要在用户的手机端长期保存一些数据,即使用户几个月后重新打开小程序,这些数据仍然存在,这时我们就需要使用微信的持久存储Storage功能。
这里我们只是对微信的Storage
进行简单的封装,并提供了setStorage
、getStorage
、clearStorageSync
、removeStorageSync
四个函数。下一篇文章中我们将会介绍基于这四个函数实现的更多工具函数。
setStorage
函数
要想把数据存储到手机的“硬盘”中,而不是内存中,可以使用setStorage
函数:
let products = utils.getCache('products')
// 保存到手机硬盘中,就算过几个月再打开小程序,数据仍然可能存在
utils.setStorage('products', products)
.then(() => console.log('保存成功'))
setStorage
函数的实现如下:
/**
* 异步设置手机硬盘持久存储。
* @param {string} key - 存储键名。
* @param {*} value - 要存储的数据。
* @param {boolean} encrypt - 是否对数据进行加密,默认为`false`。
* @returns {Promise} 返回一个Promise,成功时无返回值,失败时返回错误信息。
*/
setStorage (key, value, encrypt = false) {
return wx.setStorage({key, data: value, encrypt})
},
这里有三个参数,key
是持久存储的键名,value
是要持久存储的数据,encrypt
表示是否对数据进行加密。
我们先说第三个参数encrypt
,微信提供了加密存储的功能,当你设置encrypt
为true
时,微信会对数据进行加密存储,这样即使第三方APP访问到用户的微信持久存储数据,也无法解密,但加密存储会消耗更多的存储空间。
第二个参数value
即需要存储的数据,此数据的大小不可以超过1M,当使用加密时,value
的大小通常不可以超过0.7M。
第一个参数key
可以自定义,但这里不支持点表示法。
特别注意,虽然你可以多次调用setStorage
存储多个数据,但总存储上限为10MB。并且当你使用加密时,加密之前的数据总上限大约为7MB(这个要看加密算法会增加多少数据),总存储量大约会少3M。
getStorage
函数
当你需要读取“硬盘”上的持久存储数据时,可以使用getStorage
函数:
utils.getStorage('products')
.then(products => console.log(products))
这里有几点需要注意:
getStorage
返回的是一个Promise
;- 当调用
setStorage
时,如果encrypt
为true
,则调用getStorage
时也需要设置encrypt
为true
; - 当用户在小程序下拉页面中拖动小程序到垃圾桶时(删除小程序),
Storage
会被清空,此时getStorage
会返回undefined
。 - 微信APP可能会根据需要删除
Storage
中的数据。
删除Storage
你可以使用removeStorageSync
函数删除指定的持久存储数据:
utils.removeStorageSync('products')
或者使用clearStorageSync
函数删除所有的持久存储数据:
utils.clearStorageSync()
下篇预告
在本篇文章中,我们学习了点表示法的运用,提供了putValue
、pickValue
等函数,并演示了如何使用这些函数处理用户的config
。 但是,我们并没有把用户的config
保存到数据库中。
同样的,我们介绍了globalData.config
,但有一些配置项可能会在小程序运行期间被改变,这些配置项我们也需要保存到数据库中。
在下一篇文章中,我们继续解决这两个问题,并演示如何使用一两个简单的工具函数,就能在仅消耗1次调用次数的情况下,轻松实现用户前端config
和云端数据库的同步读写。
原文作者:微信云开发布道师刘永辉(转载请注明出处)