手撕发布-订阅模式
akino ... 2021-10-04 大约 1 分钟
# 简述
发布-订阅模式将订阅者和发布者解耦,订阅者不用一直“询问”发布者事件是否发生,而是由发布者自由决定向订阅者发送通知。
# 实现
以购物为例,买家需要向卖家购买一件商品,但是库存已经没有了,买家想要知道什么时候有货,那么买家需要隔一段时间就去问卖家有没有货,如果采用了发布-订阅模式,买家只需要将联系方式留给卖家,当卖家进货时,有卖家统一通知买家,从而减少查询次数。
# 初步实现
# 代码
class Shop {
constructor() {
this.repository = {};
}
// 订阅
$on(goods, callback) {
if (!this.repository[goods]) {
this.repository[goods] = [];
}
this.repository[goods].push(callback);
}
// 发布
$emit(goods) {
if (this.repository[goods] && this.repository[goods].length) {
this.repository[goods].forEach((cb) => cb(goods));
} else {
console.log('该商品没有客户订阅');
}
}
// 取消订阅
$removeSubscribe(goods, callback) {
if (this.repository[goods]) {
this.repository[goods] = this.repository[goods].filter(
(cb) => cb != callback
);
console.log('取消订阅成功');
}
}
// 一次性订阅
$once(goods, callback) {
let fn = (goods) => {
callback(goods);
this.$removeSubscribe(goods, fn);
};
this.$on(goods, fn);
}
}
var shop = new Shop();
shop.$on('电脑', function(goods) {
console.log(`${goods}货到啦!`);
});
shop.$once('鼠标', function(goods) {
console.log(`${goods}货到啦!`);
});
shop.$emit('电脑');
shop.$emit('鼠标');
shop.$emit('鼠标');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 输出
电脑货到啦!
鼠标货到啦!
取消订阅成功
该商品没有客户订阅
1
2
3
4
2
3
4
这里只是初步实现,还有很多地方需要完善。
# 实现订阅一组事件
只需要修改$on
函数即可
$on(goods, callback) {
if(Array.isArray(goods)) {
goods.forEach(goodsName => {
this._push(goodsName, callback);
})
} else {
this._push(goods, callback);
}
}
_push(goods, callback) {
if (!this.repository[goods]) {
this.repository[goods] = [];
}
this.repository[goods].push(callback);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16