Open ryancui92 opened 6 years ago
在 #11 中提到,通过 EventBus 可以使登录逻辑与业务接口同步起来,当然这也是小程序页面间通信的一种方式,因此需要一个 EventBus.
无非就是自己造轮子或者直接用别人的,由于一直在写 Angular,因此第一想法就是能不能把 RxJS 扔进去,那 Observable/ReplaySubject 不就随便用了吗。但其实需要用到的功能没这么多,其实就是一个简单的 publish/subscribe 就完了,于是就决定自己写一个(Google 抄一个)吧。
Observable
ReplaySubject
publish/subscribe
于是找到了微信小程序跨页面通信解决思路,里面有一个简单的实现,抄过来后我发现有几个问题可以改进:
args
Object
payload
.unsubscribe()
那就改一改吧。
思路非常相似,用一个 stores 把所有事件的回调存起来,暴露 on 用于订阅事件,emit 用于广播。跟原来的设计有变化的有:
stores
on
emit
Subscription
on()
Subscription.off()
cache
销毁订阅的实质是去 stores 里把对应的事件回调函数删掉就可以了,文章原来的方法之所以要传入回调就是去定位这个函数,后来改成了把 Page Context 传进去了。
为了定位可以简单直接一点啊,用一个自增 id 来定位就好了。因此需要一个 ID 生成器,一个简单闭包:
this.getAutoIncrese = (function() { let seq = 1; return function () { ++seq; }; })();
定位解决了,下一步就是删掉,只需要拿到这个 stores 变量就 ok 了。那就在 Subscription 里保留一份 EventBus 的实例就好了。
EventBus
class Subscription { eventBus; eventName; cbId; constructor(eventBus, eventName, cbId) { this.eventBus = eventBus; this.eventName = eventName; this.cbId = cbId; } // 销毁订阅事件 off() { this.eventBus.off(this.eventName, this.cbId); } }
整个 Subscripton 就基本完成了,这里的 off() 是直接调用 EventBus 的方法销毁。在 EventBus 的 on 方法中返回一个 Subscription 示例。
Subscripton
off()
return new Subscription(this, eventName, cbId);
当然能够允许多个参数的确更方便,但有时候约定带来的简化是明显的。
emit(eventName, payload) { const eventArray = this.stores[eventName]; if (eventArray) { eventArray.forEach(e => { e.fn.apply(null, payload); }); } }
不用关心 arguments 究竟是不是一个数据,调用 Array.from 还是 Array.prototype.slice 好,这些细节会让人抓狂。
arguments
Array.from
Array.prototype.slice
重放的逻辑也很简单,emit 的时候存起来,判断一下有没有超长,超长去掉最旧那个;on 的时候把存起来的值在新的回调上重放。
// define cache and cacheMax constructor(cacheMax) { this.cache = {}; this.cacheMax = cacheMax || 1; } // on segment: replay the emit value on new fn if (this.cache[eventName]) { this.cache[eventName].forEach(payload => { fn.apply(null, payload); }); } // emit segment: reserve the emit value if (!this.cache[eventName]) { this.cache[eventName] = []; } if (this.cache[eventName].length === this.cacheMax) { this.cache[eventName].shift(); } this.cache[eventName].push(payload);
这样一个简陋的 ReplaySubject 就搞定了。
可恶啊 登录态的获取是异步的 参照你的湿路 试一下
需要一个 EventBus
在 #11 中提到,通过 EventBus 可以使登录逻辑与业务接口同步起来,当然这也是小程序页面间通信的一种方式,因此需要一个 EventBus.
无非就是自己造轮子或者直接用别人的,由于一直在写 Angular,因此第一想法就是能不能把 RxJS 扔进去,那
Observable
/ReplaySubject
不就随便用了吗。但其实需要用到的功能没这么多,其实就是一个简单的publish/subscribe
就完了,于是就决定自己写一个(Google 抄一个)吧。需要怎样的 EventBus
于是找到了微信小程序跨页面通信解决思路,里面有一个简单的实现,抄过来后我发现有几个问题可以改进:
args
,需要传什么数据麻烦你自行包成一个Object
,只给你传payload
谢谢.unsubscribe()
就可以了吗那就改一改吧。
总体思路
思路非常相似,用一个
stores
把所有事件的回调存起来,暴露on
用于订阅事件,emit
用于广播。跟原来的设计有变化的有:Subscription
类,用于on()
的返回值,以后我们可以调用Subscription.off()
来直接销毁订阅payload
cache
来缓存所有 emit 过的值,并在新订阅者到来时重放这些值Subscription
销毁订阅的实质是去
stores
里把对应的事件回调函数删掉就可以了,文章原来的方法之所以要传入回调就是去定位这个函数,后来改成了把 Page Context 传进去了。为了定位可以简单直接一点啊,用一个自增 id 来定位就好了。因此需要一个 ID 生成器,一个简单闭包:
定位解决了,下一步就是删掉,只需要拿到这个
stores
变量就 ok 了。那就在Subscription
里保留一份EventBus
的实例就好了。整个
Subscripton
就基本完成了,这里的off()
是直接调用EventBus
的方法销毁。在EventBus
的 on 方法中返回一个Subscription
示例。只处理 payload
当然能够允许多个参数的确更方便,但有时候约定带来的简化是明显的。
不用关心
arguments
究竟是不是一个数据,调用Array.from
还是Array.prototype.slice
好,这些细节会让人抓狂。加入 Replay
重放的逻辑也很简单,emit 的时候存起来,判断一下有没有超长,超长去掉最旧那个;on 的时候把存起来的值在新的回调上重放。
这样一个简陋的
ReplaySubject
就搞定了。