小程序2.3.0版本开始支持独立分包。对于短期的活动落地页,我们会选择使用独立分包,这可以大大提升活动落地页的加载速度。
但与此同时,由于独立分包中不能依赖主包和其他分包中的内容,独立分包的使用也带来了一些数据共享问题。
遇到的问题
公用数据处理复杂
对于页面间的公用数据,我们原本的处理方式是将数据挂在App对象上。但引入了独立分包后,判断的逻辑就变得复杂了。
例如,我们想设计一个计数器counter,能够在小程序的各个地方调用。我们将结果记录在app.globalData.count,这时候需要分三种场景考虑:
-
主包和普通分包页面中,通过
getApp()
来获取App对象; -
在App对象中,通过
this
来获取App对象; -
在独立分包或App对象注册前,通过
getApp({ allowDefault: true })
来获取App对象(新的逻辑);
另外,对于3的情况,由于App对象可能未初始化,还要判断globalData、count属性是否存在。
事件被重复绑定
通过wx.onError、wx.onPageNotFound等方法可以监控小程序的运行情况,我们把这些能力封装在npm包中。
export function report() {
// 各种处理逻辑
// ....
}
wx.onError(report);
复制代码
当独立分包和主包都引入了这个npm包,而npm包中调用wx.onXXXX方法进行了绑定,我们可以想到,当用户在独立分包和主包页面之间跳转时,事件的处理函数会被绑定不止一次(主包一次,每个独立分包一次)。
解决思路
-
对于需要在主包、独立分包公用数据的情况,我们考虑将不同场景下读写app对象的能力封装起来,这类似于一个SessionStorage,我们可以在任意场景操作SessionStorage里的公用数据,而数据会在小程序从冷启动到销毁的运行过程中一直保留。
-
对于事件重复绑定的问题,我们使用sessionStorage中的一个key来加锁。实现一个once方法,保证同一个key的逻辑只执行一次,通过如下的方式来调用
export function report() { // 各种处理逻辑 // .... } once('_wx_onerror_key_',() => { wx.onError(report); }); 复制代码
具体实现
- 为了不与原有的globalData冲突,我们使用一个新的BASIC_KEY,作为App对象上的属性名,来存储sessionStorage的内容。
- 默认以getApp({ allowDefault: true })获取App对象,为了满足在App()内调用时也能取到正确的App对象,我们可以在App.onLaunch方法时将this传入
sessionStorage.setApp(this)
。 - 暴露的api对齐浏览器的sessionStorage,实现如下:
const BASIC_KEY = '_imwxutils_sessionStorageData_';
let app = getApp({ allowDefault: true }) || {};
app[BASIC_KEY] = app[BASIC_KEY] || {};
export function setApp(customApp) {
customApp[BASIC_KEY] = customApp[BASIC_KEY] || app[BASIC_KEY] || {};
app = customApp;
}
export function setItem(key,value) {
app[BASIC_KEY][key] = value;
}
export function getItem(key) {
return app[BASIC_KEY][key];
}
export function removeItem(key) {
app[BASIC_KEY][key] = null;
}
export function clear() {
app[BASIC_KEY] = {};
}
复制代码
基于sessionStorage我们又可以实现once方法:
import * as sessionStorage from './session-storage';
const ONCE_BASIC_KEY = '_imwxutils_once_record_';
/**
* 全局只执行一次的方法
*/
function once(key,func) {
if (!key) {
return;
}
const record = sessionStorage.getItem(ONCE_BASIC_KEY) || {};
if (record[key]) { // 之前执行过了
return;
}
record[key] = true;
sessionStorage.setItem(ONCE_BASIC_KEY,record);
func();
}
复制代码
以上,通过实现sessionStorage和once方法,我们解决了独立分包与主包之间数据共享以及事件绑重复定的问题。
欢迎交流