点击查看:小打卡 | 如何基于微信原生构建应用级小程序底层架构(上)
装饰模式
可能有朋友会好奇装饰器和我们接下来要做的原生函数扩展有什么关系?
先看下装饰模式的定义:在不改变原函数的基础上,附加一些额外的功能
方便更好的理解
创建一个函数,然后将存在originF这个变量里,并对它重新赋值,最后执行,最后的执行直接结果是什么?
hello world!!
这样做的好处是什么,我们对函数f添加了一个新的功能,但是我们没有对原函数进行任何的修改
那么对于小程序的应用
照猫画虎一下,同样的将小程序原生的Page函数存起来,再重新赋值,看下结果,发现Page执行的时候每次都会console这句话,我这里有两个未分包的页面,就执行了2次
回归到刚开始需要解决的问题,“多个页面pv,uv如何监控,不可能每个页面都要手动收集”,
pv怎么算,pv的意思是页面浏览量,也就是需要页面生成时,对应到小程序生命周期就是onLoad
刚才我们做到了每个Page执行时添加功能,但是怎么在onLoad时进行数据统计呢?
同样的可以用装饰函数修饰page里面的函数方法
[图1] 这个data就是我们实际在pages下写的业务逻辑对象,我们先拿到该页面的key名来进行遍历,首先排除掉非函数,拿到onLoad函数,这时候对它进行扩展,这时候每一个页面执行onLoad的时候都会console一次字符串,当然也可以替换为你想要的任何功能
[图2] 其实我们可以再优化一下,比如抽出一个对象,将你想要装饰的函数写入其中,如果原函数存在则进行装饰,如果不存在则直接赋值,这个抽出来的对象其实可以算是另一种继承方式的实现
它的意义在于
帮助我们开辟了一块公有空间,帮助我们扩展Page对象,并且可以劫持任意方法,在不修改原业务函数代码的情况下增加新的逻辑
其次也是最重要的是,我们完全不需要处理历史包袱
一个应用场景
左边是微信原生的分享方法
遇到的一些问题: 不便于扩展,多个分享策略时,代码块过大,并且分享的通用数据需要每个页面单独处理,例如统计回流信息需要的分享页面信息,事件信息
右边是依赖于我们刚刚开辟的公有空间里填写的公共方法,函数很简单,获得参数,获得页面分享策略,执行,顺便还做了obj转url的处理,避免了纯url书写长路径时的尴尬
思考
既然能扩展Page对象,那么App,Component甚至wx全局对象下的方法呢?
有兴趣的朋友可以下来想一下
跨页面 / 多页面事件通知
我这边简单提一下跨页面通知的问题,这个应该算是很多小程序开发者遇到的通用问题,我问过的一些人,大部分是使用下面这两种方法,一种是getCurrentPages 页面栈队列,二种onShow upData global里的存储的数据,不管哪一种在业务复杂的情况下都会引起一定的问题,比如第一种的多级入口,第二种的话属于无效判断和及时性
小打卡这边用的简版的event Bus,一个只有80行代码的订阅方法,
左图是一个简单的示例,大致上就是分两种角色,订阅者和发布者,中间依靠任务队列联系,每次发布者推送消息,订阅者都会收到通知和相应的数据
其实单纯的event bus也有很多的问题,比如:
- 业务复杂情况下过于频繁,对业务代码侵入频繁,可以想像一下到处都是on,off, emit场景
- 解绑需要树立规范,但是人总是会犯错,容易绑定后忘记解绑或重复绑定的问题,比较浪费内存,对性能也有消耗
结合公共空间
我们已知可以对生命周期进行扩展的时候怎么去解决这个问题
其实订阅必然是和页面结合,因为在页面不存在的情况下,发送通知也不会有反馈,
如何证明页面存在自然是onLoad 和 onUnload
按照这个逻辑我们只需要在onLoad和onShow做些处理即可
[图1] 先看右侧业务代码,按照策略注册了一个函数集合,在执行onLoad时,自动将业务内的onRss函数遍历,自定绑定订阅,并推到一个缓存数组内
onUnload时遍历缓存,自动解绑
这时订阅与页面的生命周期强绑定,我们不再需要处理解绑事件,也不需要在业务内插入订阅代码,只需要管理好当前页面的订阅策略即可
技术选型
没有哪一种一定正确的方案,在选型的时候可能需要考虑到上面大致6种元素, 总之选择最适合自己团队方案非常重要
一些小贴士:开发要尽量避免过度设计, 应根据实际需求, 比如之前在写现在这个简版的event bus库的时候设计了很多奇奇怪怪的
功能,现在2年过去还没用到
小程序和浏览器,node本质上是相通的,可以多借鉴和参考
The End
今天我的分享就到此结束,算是这段时间对小程序开发上的一点心得体会,谢谢