grofc_utils 1.6.1 → 1.6.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/event.js +38 -29
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grofc_utils",
3
- "version": "1.6.1",
3
+ "version": "1.6.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/event.js CHANGED
@@ -1,4 +1,4 @@
1
- import { isPlainObject, throwIfIsNotExpectedValue, throwIfIsNotFunction, throwIfIsNotPlainObject, throwIfIsNotString } from "./guard.js"
1
+ import { isPlainObject, throwIfIsNotExpectedValue, throwIfIsNotFunction, throwIfIsNotPlainObject, throwIfIsNotString, throwIfSomeKeysMissing } from "./guard.js"
2
2
  import { assignWithDescriptors } from "./object.js";
3
3
  import { randomString } from "./random.js";
4
4
 
@@ -15,18 +15,43 @@ import { randomString } from "./random.js";
15
15
  * )=>object
16
16
  * on:(event:string,phase:"before"|"begin"|"end"|"after",{
17
17
  * name:string
18
- * filter:(event:{
18
+ * filter?:(event:{
19
19
  * target,name:string,type:string|null,preData:object,data:object
20
20
  * })
21
21
  * callback:(event:{
22
22
  * target,name:string,type:string|null,preData:object,data:object
23
23
  * })=>void
24
+ * once?:boolean
24
25
  * })=>void
25
26
  * off:(event:string,phase:"before"|"begin"|"end"|"after",name:string)=>void
26
27
  * }} 包含dispatchSync, on, off方法的对象
27
28
  */
28
29
  export function createEventEmitter() {
29
30
  const listenerMap = new Map()
31
+ const on = (event, phase, listener = {}) => {
32
+ throwIfIsNotString(event, "event");
33
+ throwIfIsNotExpectedValue(phase, "phase", "before", "begin", "end", "after");
34
+ throwIfSomeKeysMissing(listener, ["name", "callback"], "listener")
35
+ const eventName = event + ":" + phase;
36
+ const listenerList = listenerMap.get(eventName)
37
+ if (Array.isArray(listenerList)) {
38
+ listenerList.push(listener)
39
+ } else {
40
+ listenerMap.set(eventName, [listener]);
41
+ }
42
+ }
43
+ const off = (event, phase, name) => {
44
+ throwIfIsNotString(event, "event");
45
+ throwIfIsNotExpectedValue(phase, "phase", "before", "begin", "end", "after");
46
+ throwIfIsNotString(name, "name")
47
+ const eventName = event + ":" + phase;
48
+ const list = listenerMap.get(eventName);
49
+ if (Array.isArray(list)) {
50
+ const index = list.findIndex(o => o.name === name)
51
+ if (index !== -1) list.splice(index, 1);
52
+ if (list.length === 0) listenerMap.delete(eventName);
53
+ }
54
+ };
30
55
  const dispatchSync = (event, ing = () => { }, options = {}) => {
31
56
  throwIfIsNotString(event, "event");
32
57
  throwIfIsNotFunction(ing, "ing");
@@ -63,9 +88,11 @@ export function createEventEmitter() {
63
88
  }
64
89
  }, baseEvent)
65
90
  const beforeListenerList = listenerMap.get(event + ":before") ?? [];
66
- for (const { filter, callback } of beforeListenerList) {
91
+ for (const { name, filter, callback, once } of beforeListenerList.slice()) {
67
92
  if (filter?.(beforeEvent) === false) continue;
68
- if (callback(beforeEvent) === false && beforeEvent.status.cancellable) return;
93
+ const toCancel = callback(beforeEvent);
94
+ if (once) off(event, "before", name)
95
+ if (toCancel === false && beforeEvent.status.cancellable) return;
69
96
  }
70
97
  // 触发begin阶段监听器
71
98
  const beginEvent = assignWithDescriptors({
@@ -74,9 +101,10 @@ export function createEventEmitter() {
74
101
  }
75
102
  }, baseEvent);
76
103
  const beginListenerList = listenerMap.get(event + ":begin") ?? [];
77
- for (const { callback, filter } of beginListenerList) {
104
+ for (const { name, callback, filter, once } of beginListenerList.slice()) {
78
105
  if (filter?.(beginEvent) === false) continue;
79
106
  callback(beginEvent)
107
+ if (once) off(event, "begin", name)
80
108
  }
81
109
  // 执行ing阶段函数并获取当前数据
82
110
  const ingEvent = assignWithDescriptors({
@@ -96,9 +124,10 @@ export function createEventEmitter() {
96
124
  }
97
125
  }, baseEvent)
98
126
  const endListenerList = listenerMap.get(event + ":end") ?? []
99
- for (const { callback, filter } of endListenerList) {
127
+ for (const { name, callback, filter, once } of endListenerList.slice()) {
100
128
  if (filter?.(endEvent) === false) continue;
101
129
  callback(endEvent)
130
+ if (once) off(event, "end", name)
102
131
  }
103
132
  // 触发after阶段监听器,并处理可能的递归事件调用
104
133
  const afterEvent = assignWithDescriptors({
@@ -110,37 +139,17 @@ export function createEventEmitter() {
110
139
  }
111
140
  }, baseEvent);
112
141
  const afterListenerList = listenerMap.get(event + ":after") ?? [];
113
- for (const { callback, filter } of afterListenerList) {
142
+ for (const { name, callback, filter, once } of afterListenerList.slice()) {
114
143
  if (filter?.(afterEvent) === false) continue;
115
144
  const result = callback(afterEvent)
145
+ if (once) off(event, "after", name)
116
146
  if (!isPlainObject(result)) continue;
117
147
  const { event, ing, options } = result;
118
148
  if (typeof event !== "string") continue;
119
149
  dispatchSync(event, ing, options)
120
150
  }
121
151
  }
122
- const on = (event, phase, listener = {}) => {
123
- throwIfIsNotString(event, "event");
124
- throwIfIsNotExpectedValue(phase, "phase", "before", "begin", "end", "after");
125
- const eventName = event + ":" + phase;
126
- const listenerList = listenerMap.get(eventName)
127
- if (Array.isArray(listenerList)) {
128
- listenerList.push(listener)
129
- } else {
130
- listenerMap.set(eventName, [listener]);
131
- }
132
- }
133
- const off = (event, phase, name) => {
134
- throwIfIsNotString(event, "event");
135
- throwIfIsNotExpectedValue(phase, "phase", "before", "begin", "end", "after");
136
- const eventName = event + ":" + phase;
137
- const list = listenerMap.get(eventName);
138
- if (Array.isArray(list)) {
139
- const index = list.findIndex(o => o.name === name)
140
- if (index !== -1) list.splice(index, 1);
141
- if (list.length === 0) listenerMap.delete(eventName);
142
- }
143
- };
152
+
144
153
  return {
145
154
  dispatchSync,
146
155
  on,