cbvirtua 1.0.93 → 1.0.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mi.txt ADDED
@@ -0,0 +1,374 @@
1
+ export default function mitt(all){
2
+ //使用Map存储注册的事件
3
+ all = all || new Map();
4
+
5
+
6
+ return {
7
+ all,
8
+ on(type, handler, priority = 0, listener) {
9
+ const handlers = all!.get(type) || [];
10
+ handlers.push({handler, priority});
11
+ handlers.sort((a, b) => b.priority - a.priority);
12
+ all!.set(type, handlers);
13
+ if (listener) {
14
+ listener({type, handler, priority});
15
+ }
16
+ },
17
+
18
+ off(type, handler) {
19
+ const handlers = all!.get(type);
20
+ if (handlers) {
21
+ if (handler) {
22
+ const index = handlers.findIndex(item => item.handler === handler);
23
+ handlers.splice(index > -1 ? index : 0, 1);
24
+ }
25
+ else {
26
+ all!.set(type, []);
27
+ }
28
+ }
29
+ },
30
+
31
+ emit(type, evt, listener) {
32
+ if (listener) {
33
+ listener({type, evt});
34
+ }
35
+ let handlers = all!.get(type);
36
+ if (handlers) {
37
+ handlers.slice().map(async (handler) => {
38
+ await handler(evt);
39
+ });
40
+ }
41
+ }
42
+ };
43
+ }
44
+
45
+
46
+ function eventListener({type, handler, priority}) {
47
+ console.log(`事件 ${type} 已注册,处理函数为 ${handler},优先级为 ${priority}`);
48
+ }
49
+
50
+
51
+ function eventTriggerListener({type, evt}) {
52
+ console.log(`事件 ${type} 已触发,事件对象为 ${evt}`);
53
+ }
54
+
55
+
56
+ const bus = mitt();
57
+
58
+
59
+ bus.on('click', () => console.log('点击事件已触发'), 1, eventListener);
60
+ bus.emit('click', {target: '按钮'}, eventTriggerListener);
61
+
62
+
63
+
64
+ 前言
65
+ 这是一个很小型的发布订阅库 https://github.com/developit/mitt。
66
+
67
+ 是的它很小只有 200b,既然小当然功能简洁。作者为了压缩后文件大小绝对不能大于 200b 所以社区提的功能请求并没有解决,这次除了看源码外,再尝试解决一下未实现的功能请求 Async extension for mitt。
68
+
69
+ 环境
70
+ 依赖包内置了 ts-node 如果想直接运行 ts 的文件了使用 npx ts-node xxx.ts。
71
+
72
+ 源码
73
+ 类型声明
74
+ 从类型声明就可以大概看出存储的什么结构,有一个总集合 Map,Map 的一个 Key 对应多个回调函数。
75
+
76
+ // 事件类型
77
+ export type EventType = string | symbol;
78
+
79
+ // 基础回调函数
80
+ export type Handler<T = unknown> = (event: T) => void;
81
+ // 通配符回调函数
82
+ export type WildcardHandler<T = Record<string, unknown>> = (
83
+ type: keyof T,
84
+ event: T[keyof T]
85
+ ) => void;
86
+
87
+ // 基础回调集合
88
+ export type EventHandlerList<T = unknown> = Array<Handler<T>>;
89
+ // 通配符的回调集合
90
+ export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>;
91
+
92
+ // 事件类型和回调的映射 { foo: [fn1, fn2] }
93
+ export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
94
+ keyof Events | "*",
95
+ EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
96
+ >;
97
+
98
+ // Emitter 实例类型
99
+ export interface Emitter<Events extends Record<EventType, unknown>> {
100
+ all: EventHandlerMap<Events>;
101
+
102
+ // 函数重载 "on"
103
+ // 类型约束 Key extends keyof Events
104
+ // 索引类型查询操作符 keyof Events
105
+ // 索引访问操作符 Events[Key]
106
+ on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;
107
+ on(type: "*", handler: WildcardHandler<Events>): void;
108
+
109
+ off<Key extends keyof Events>(type: Key,handler?: Handler<Events[Key]>): void;
110
+ off(type: "*", handler: WildcardHandler<Events>): void;
111
+
112
+ emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;
113
+ emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void;
114
+ }
115
+ 功能实现
116
+ on
117
+ on 的作用就是以 type 为键和分类把回调收集起来。
118
+
119
+ export default function mitt<Events extends Record<EventType, unknown>>(): Emitter<Events> {
120
+ all = all || new Map();
121
+ return {
122
+ on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) {
123
+ // 获取到对应类型集合
124
+ const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
125
+ // 如果已存在,直接 push 追加
126
+ if (handlers) {
127
+ handlers.push(handler);
128
+ } else {
129
+ // 反之,创建一个新的集合
130
+ all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
131
+ }
132
+ },
133
+ };
134
+ }
135
+ off
136
+ off 的作用就是根据 type 找到对应的函数从集合中删除,如果没传入回调则全部删除。
137
+
138
+ 关于 handlers.indexOf(handler) >>> 0,这有一遍文章 https://segmentfault.com/a/1190000014613703。
139
+
140
+ export default function mitt<Events extends Record<EventType, unknown>>(): Emitter<Events> {
141
+ all = all || new Map();
142
+ return {
143
+ off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) {
144
+ // 获取到对应类型集合
145
+ const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
146
+ if (handlers) {
147
+ if (handler) {
148
+ // 回调存在,找到对应的函数删除,只删除一个。
149
+ // 关于 -1 >>> 0 : https://segmentfault.com/a/1190000014613703
150
+ handlers.splice(handlers.indexOf(handler) >>> 0, 1);
151
+ } else {
152
+ // 不存在清空此类型收集的回调
153
+ all!.set(type, []);
154
+ }
155
+ }
156
+ },
157
+ };
158
+ }
159
+ emit
160
+ emit 的作用就是以 type 获取到对应的集合,依次运行对应的函数。
161
+
162
+ 关于为什么要用一次 slice developit/mitt#109。
163
+
164
+ export default function mitt<Events extends Record<EventType, unknown>>(): Emitter<Events> {
165
+ all = all || new Map();
166
+ return {
167
+ emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
168
+ let handlers = all!.get(type);
169
+ if (handlers) {
170
+ (handlers as EventHandlerList<Events[keyof Events]>)
171
+ // Why use slice: https://github.com/developit/mitt/pull/109
172
+ .slice()
173
+ // 执行对应类型的所有回调
174
+ .map((handler) => {
175
+ handler(evt!);
176
+ });
177
+ }
178
+
179
+ // 每次派发都执行通配符的回调
180
+ handlers = all!.get("*");
181
+ if (handlers) {
182
+ (handlers as WildCardEventHandlerList<Events>)
183
+ .slice()
184
+ .map((handler) => {
185
+ handler(type, evt!);
186
+ });
187
+ }
188
+ },
189
+ };
190
+ }
191
+ 功能扩展
192
+ 在翻看 Issues 的时候发现有两个功能讨论的比较多(也有给出方案但感觉不完善),有用也是有用就是作者不想大小不想超过预期。所以啊作者不实现的我们就得根据自己的需要去改。所以我对这两个功能尝试在不改动源码的情况下去解决,现在用不到以后不一定了。
193
+
194
+ once
195
+ once 是只触发一次。所以实现就是触发一次之后立刻解除监听。实现方式为对原始的功能进行包装。
196
+
197
+ import mitt from "../src/index";
198
+ import type { EventType, EventHandlerMap, Emitter, Handler } from '../src/index';
199
+
200
+ // 继承 Emitter 基础接口
201
+ export interface EmitterOnce<Events extends Record<EventType, unknown>> extends Emitter<Events> {
202
+ once<Key extends keyof Events>(type: Key,handler: Handler<Events[Key]>): void;
203
+ }
204
+
205
+ export default function mittOnce<Events extends Record<EventType, unknown>>(
206
+ all?: EventHandlerMap<Events>
207
+ ): EmitterOnce<Events> {
208
+ const emitter = mitt<Events>(all);
209
+
210
+ return {
211
+ // 原始方法
212
+ ...emitter,
213
+
214
+ // 扩展 once
215
+ once<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>) {
216
+ const fn = (arg: Events[Key]) => {
217
+ // 执行一次,立刻解除监听
218
+ emitter.off(type, fn);
219
+ handler(arg);
220
+ };
221
+ emitter.on(type, fn);
222
+ },
223
+ };
224
+ }
225
+ 测试示例和结果如下。
226
+
227
+ import mittOnce from "./once";
228
+
229
+ type Events = {
230
+ foo?: string;
231
+ };
232
+
233
+ const emitter = mittOnce<Events>();
234
+
235
+ function A() {
236
+ console.log("A");
237
+ }
238
+
239
+ function B() {
240
+ console.log("B");
241
+ }
242
+
243
+ emitter.on("foo", A);
244
+ emitter.once("foo", B);
245
+ emitter.emit("foo"); // A B
246
+ emitter.emit("foo"); // A
247
+ async
248
+ 比如我要 emit 事件,我还想知道触发的事件是否全部执行完毕了。这里我扩展了两个 api 分别是 串行(emitSerial) 和并行(emitParallel)。这两个功能都是对原始的函数使用 Promise 去执行。
249
+
250
+ import mitt from "../src/index";
251
+ import type { EventType, EventHandlerMap, Emitter, EventHandlerList, WildCardEventHandlerList } from '../src/index';
252
+
253
+ // 继承 Emitter 基础接口
254
+ export interface EmitterAsync<Events extends Record<EventType, unknown>>
255
+ extends Emitter<Events> {
256
+ emitSerial<Key extends keyof Events>(type: Key, event: Events[Key]): Promise<void>;
257
+ emitSerial<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): Promise<void>;
258
+
259
+ emitParallel<Key extends keyof Events>(type: Key, event: Events[Key]): Promise<void>;
260
+ emitParallel<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): Promise<void>;
261
+ }
262
+
263
+ export default function mittAsync<Events extends Record<EventType, unknown>>(
264
+ all?: EventHandlerMap<Events>
265
+ ): EmitterAsync<Events> {
266
+ const emitter = mitt<Events>(all);
267
+
268
+ return {
269
+ // 原始方法
270
+ ...emitter,
271
+
272
+ // 串行 Promise.then().then()
273
+ async emitSerial<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
274
+ let handlers = emitter.all!.get(type);
275
+ if (handlers) {
276
+ const callbacks = (handlers as EventHandlerList<Events[keyof Events]>).slice();
277
+ // compose run
278
+ await callbacks.reduce(
279
+ (promise, callback) => promise.then(() => callback(evt!)),
280
+ Promise.resolve()
281
+ );
282
+ }
283
+
284
+ // 每次派发都执行通配符的回调
285
+ handlers = emitter.all!.get("*");
286
+ if (handlers) {
287
+ const callbacks = (handlers as WildCardEventHandlerList<Events>).slice();
288
+ // compose run
289
+ await callbacks.reduce(
290
+ (promise, callback) => promise.then(() => callback(type, evt!)),
291
+ Promise.resolve()
292
+ );
293
+ }
294
+ },
295
+
296
+ // 并行 Promise.all
297
+ async emitParallel<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
298
+ let handlers = emitter.all!.get(type);
299
+ if (handlers) {
300
+ const callbacks = (handlers as EventHandlerList<Events[keyof Events]>).slice();
301
+ // Promise.all run
302
+ await Promise.all(
303
+ callbacks.map((handler) => Promise.resolve(handler(evt!)))
304
+ );
305
+ }
306
+
307
+ // 每次派发都执行通配符的回调
308
+ handlers = emitter.all!.get("*");
309
+ if (handlers) {
310
+ const callbacks = (handlers as WildCardEventHandlerList<Events>).slice();
311
+ // Promise.all run
312
+ await Promise.all(
313
+ callbacks.map((handler) => Promise.resolve(handler(type, evt!)))
314
+ );
315
+ }
316
+ },
317
+ };
318
+ }
319
+ 测试示例和结果如下。
320
+
321
+ import mittAsync from "./async";
322
+
323
+ type Events = {
324
+ foo?: string;
325
+ };
326
+
327
+ const emitter = mittAsync<Events>();
328
+
329
+ async function A() {
330
+ await new Promise((reslove) => {
331
+ setTimeout(() => {
332
+ console.log("A");
333
+ reslove("A");
334
+ }, 2000);
335
+ });
336
+ }
337
+
338
+ function B() {
339
+ return new Promise((reslove) => {
340
+ setTimeout(() => {
341
+ console.log("B");
342
+ reslove("B");
343
+ }, 1000);
344
+ });
345
+ }
346
+
347
+ function C() {
348
+ console.log("C");
349
+ }
350
+
351
+ emitter.on("foo", A);
352
+ emitter.on("foo", B);
353
+ emitter.on("foo", C);
354
+
355
+ // 原始 C D B A
356
+ emitter.emit("foo");
357
+ console.log("D");
358
+
359
+ // 串行 A B C D
360
+ (async () => {
361
+ await emitter.emitSerial("foo");
362
+ console.log("D");
363
+ })();
364
+
365
+ // 并行 C B A D
366
+ (async () => {
367
+ emitter.emitParallel("foo").then(() => {
368
+ console.log("D");
369
+ });
370
+ })();
371
+ 总结
372
+ 高级类型平常用业务的不多,一般也就类库中应用的多,也学也忘了刚好回顾下。
373
+
374
+ 扩展功能中用到了 compose 刚好是对前几期源码的应用。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cbvirtua",
3
- "version": "1.0.93",
3
+ "version": "1.0.95",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
Binary file
Binary file
Binary file
Binary file