@idlebox/common 1.4.1 → 1.4.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.
@@ -7,6 +7,7 @@ exports.Emitter = void 0;
7
7
  */
8
8
  class Emitter {
9
9
  _callbacks = [];
10
+ executing = false;
10
11
  constructor() {
11
12
  this.handle = this.handle.bind(this);
12
13
  }
@@ -21,14 +22,24 @@ class Emitter {
21
22
  * @param data 回调数据
22
23
  */
23
24
  fire(data) {
24
- for (const callback of this._callbacks) {
25
- callback(data);
25
+ this.requireNotExecuting();
26
+ this.executing = true;
27
+ try {
28
+ for (const callback of this._callbacks) {
29
+ callback(data);
30
+ }
31
+ }
32
+ finally {
33
+ this.doDefer();
34
+ this.executing = false;
26
35
  }
27
36
  }
28
37
  /**
29
38
  * 与 `fire()`相同,但是忽略任何错误,并且即便出错也继续执行全部callback
30
39
  */
31
40
  fireNoError(data) {
41
+ this.requireNotExecuting();
42
+ this.executing = true;
32
43
  for (const callback of this._callbacks) {
33
44
  try {
34
45
  callback(data);
@@ -37,6 +48,8 @@ class Emitter {
37
48
  console.error('Error ignored: ', e);
38
49
  }
39
50
  }
51
+ this.doDefer();
52
+ this.executing = false;
40
53
  }
41
54
  /**
42
55
  * 获取handle()方法的引用
@@ -49,17 +62,54 @@ class Emitter {
49
62
  * @param callback 回调函数
50
63
  */
51
64
  handle(callback) {
52
- this._callbacks.unshift(callback);
65
+ this.requireNotExecuting();
66
+ let disposed = false;
67
+ this._callbacks.unshift((e) => {
68
+ if (!disposed)
69
+ callback(e);
70
+ });
71
+ const realDispose = () => {
72
+ const index = this._callbacks.indexOf(callback);
73
+ if (index !== -1) {
74
+ this._callbacks.splice(index, 1);
75
+ }
76
+ };
53
77
  return {
54
78
  dispose: () => {
55
- const index = this._callbacks.indexOf(callback);
56
- if (index !== -1) {
57
- this._callbacks.splice(index, 1);
79
+ disposed = true;
80
+ if (this.executing) {
81
+ this.defer(realDispose);
82
+ }
83
+ else {
84
+ realDispose();
58
85
  }
59
86
  },
60
87
  };
61
88
  }
89
+ /**
90
+ * 注册一次性回调
91
+ * @param callback 回调函数
92
+ */
93
+ once(callback) {
94
+ this.requireNotExecuting();
95
+ const disposable = this.handle((data) => {
96
+ callback(data);
97
+ disposable.dispose();
98
+ });
99
+ return disposable;
100
+ }
101
+ defers = [];
102
+ defer(fn) {
103
+ this.defers.push(fn);
104
+ }
105
+ doDefer() {
106
+ for (const fn of this.defers) {
107
+ fn();
108
+ }
109
+ this.defers.length = 0;
110
+ }
62
111
  dispose() {
112
+ this.requireNotExecuting();
63
113
  this._callbacks.length = 0;
64
114
  this.fireNoError =
65
115
  this.fire =
@@ -68,6 +118,11 @@ class Emitter {
68
118
  throw new Error('Event is disposed');
69
119
  };
70
120
  }
121
+ requireNotExecuting() {
122
+ if (this.executing) {
123
+ throw new Error('conflict state, emitter is firing');
124
+ }
125
+ }
71
126
  }
72
127
  exports.Emitter = Emitter;
73
128
  //# sourceMappingURL=event.cjs.map
@@ -6,5 +6,5 @@
6
6
  "../../../../src/lifecycle/event/event.ts"
7
7
  ],
8
8
  "names": [],
9
- "mappings": ";;;AAUA;;;GAGG;AACH,MAAa,OAAO;IACA,UAAU,GAAsB,EAAE,CAAC;IAEtD;QACC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACI,aAAa;QACnB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACI,IAAI,CAAC,IAAO;QAClB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;IACF,CAAC;IAED;;OAEG;IACI,WAAW,CAAC,IAAO;QACzB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,CAAC;gBACJ,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;YACrC,CAAC;QACF,CAAC;IACF,CAAC;IAED;;OAEG;IACH,IAAI,QAAQ;QACX,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,QAAyB;QAC/B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClC,OAAO;YACN,OAAO,EAAE,GAAG,EAAE;gBACb,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAChD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;oBAClB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAClC,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;IAED,OAAO;QACN,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,WAAW;YACf,IAAI,CAAC,IAAI;gBACT,IAAI,CAAC,MAAM;oBACV,GAAG,EAAE;wBACJ,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;oBACtC,CAAC,CAAC;IACL,CAAC;CACD;AArED,0BAqEC"
9
+ "mappings": "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"
10
10
  }
@@ -5,12 +5,14 @@ export interface EventHandler<T> {
5
5
  export interface EventRegister<T> {
6
6
  (callback: EventHandler<T>): IDisposable;
7
7
  }
8
+ type DeferFn = () => void;
8
9
  /**
9
10
  * 事件注册对象
10
11
  * @public
11
12
  */
12
13
  export declare class Emitter<T> implements IDisposable {
13
14
  protected readonly _callbacks: EventHandler<T>[];
15
+ private executing;
14
16
  constructor();
15
17
  /**
16
18
  * @returns 当前注册回调数量
@@ -34,6 +36,16 @@ export declare class Emitter<T> implements IDisposable {
34
36
  * @param callback 回调函数
35
37
  */
36
38
  handle(callback: EventHandler<T>): IDisposable;
39
+ /**
40
+ * 注册一次性回调
41
+ * @param callback 回调函数
42
+ */
43
+ once(callback: EventHandler<T>): IDisposable;
44
+ private defers;
45
+ defer(fn: DeferFn): void;
46
+ private doDefer;
37
47
  dispose(): void;
48
+ private requireNotExecuting;
38
49
  }
50
+ export {};
39
51
  //# sourceMappingURL=event.d.ts.map
@@ -6,5 +6,5 @@
6
6
  "../../../../src/lifecycle/event/event.ts"
7
7
  ],
8
8
  "names": [],
9
- "mappings": "AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,WAAW,YAAY,CAAC,CAAC;IAC9B,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC;CACzC;AAED;;;GAGG;AACH,qBAAa,OAAO,CAAC,CAAC,CAAE,YAAW,WAAW;IAC7C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAM;;IAMtD;;OAEG;IACI,aAAa;IAIpB;;;OAGG;IACI,IAAI,CAAC,IAAI,EAAE,CAAC;IAMnB;;OAEG;IACI,WAAW,CAAC,IAAI,EAAE,CAAC;IAU1B;;OAEG;IACH,IAAI,QAAQ,IAAI,aAAa,CAAC,CAAC,CAAC,CAE/B;IAED;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW;IAY9C,OAAO;CASP"
9
+ "mappings": "AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,WAAW,YAAY,CAAC,CAAC;IAC9B,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC;CACzC;AAED,KAAK,OAAO,GAAG,MAAM,IAAI,CAAC;AAE1B;;;GAGG;AACH,qBAAa,OAAO,CAAC,CAAC,CAAE,YAAW,WAAW;IAC7C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAM;IACtD,OAAO,CAAC,SAAS,CAAkB;;IAMnC;;OAEG;IACI,aAAa;IAIpB;;;OAGG;IACI,IAAI,CAAC,IAAI,EAAE,CAAC;IAanB;;OAEG;IACI,WAAW,CAAC,IAAI,EAAE,CAAC;IAc1B;;OAEG;IACH,IAAI,QAAQ,IAAI,aAAa,CAAC,CAAC,CAAC,CAE/B;IAED;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW;IAwB9C;;;OAGG;IACH,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW;IAS5C,OAAO,CAAC,MAAM,CAAiB;IACxB,KAAK,CAAC,EAAE,EAAE,OAAO;IAGxB,OAAO,CAAC,OAAO;IAOf,OAAO;IAWP,OAAO,CAAC,mBAAmB;CAK3B"
10
10
  }
@@ -4,6 +4,7 @@
4
4
  */
5
5
  export class Emitter {
6
6
  _callbacks = [];
7
+ executing = false;
7
8
  constructor() {
8
9
  this.handle = this.handle.bind(this);
9
10
  }
@@ -18,14 +19,24 @@ export class Emitter {
18
19
  * @param data 回调数据
19
20
  */
20
21
  fire(data) {
21
- for (const callback of this._callbacks) {
22
- callback(data);
22
+ this.requireNotExecuting();
23
+ this.executing = true;
24
+ try {
25
+ for (const callback of this._callbacks) {
26
+ callback(data);
27
+ }
28
+ }
29
+ finally {
30
+ this.doDefer();
31
+ this.executing = false;
23
32
  }
24
33
  }
25
34
  /**
26
35
  * 与 `fire()`相同,但是忽略任何错误,并且即便出错也继续执行全部callback
27
36
  */
28
37
  fireNoError(data) {
38
+ this.requireNotExecuting();
39
+ this.executing = true;
29
40
  for (const callback of this._callbacks) {
30
41
  try {
31
42
  callback(data);
@@ -34,6 +45,8 @@ export class Emitter {
34
45
  console.error('Error ignored: ', e);
35
46
  }
36
47
  }
48
+ this.doDefer();
49
+ this.executing = false;
37
50
  }
38
51
  /**
39
52
  * 获取handle()方法的引用
@@ -46,17 +59,54 @@ export class Emitter {
46
59
  * @param callback 回调函数
47
60
  */
48
61
  handle(callback) {
49
- this._callbacks.unshift(callback);
62
+ this.requireNotExecuting();
63
+ let disposed = false;
64
+ this._callbacks.unshift((e) => {
65
+ if (!disposed)
66
+ callback(e);
67
+ });
68
+ const realDispose = () => {
69
+ const index = this._callbacks.indexOf(callback);
70
+ if (index !== -1) {
71
+ this._callbacks.splice(index, 1);
72
+ }
73
+ };
50
74
  return {
51
75
  dispose: () => {
52
- const index = this._callbacks.indexOf(callback);
53
- if (index !== -1) {
54
- this._callbacks.splice(index, 1);
76
+ disposed = true;
77
+ if (this.executing) {
78
+ this.defer(realDispose);
79
+ }
80
+ else {
81
+ realDispose();
55
82
  }
56
83
  },
57
84
  };
58
85
  }
86
+ /**
87
+ * 注册一次性回调
88
+ * @param callback 回调函数
89
+ */
90
+ once(callback) {
91
+ this.requireNotExecuting();
92
+ const disposable = this.handle((data) => {
93
+ callback(data);
94
+ disposable.dispose();
95
+ });
96
+ return disposable;
97
+ }
98
+ defers = [];
99
+ defer(fn) {
100
+ this.defers.push(fn);
101
+ }
102
+ doDefer() {
103
+ for (const fn of this.defers) {
104
+ fn();
105
+ }
106
+ this.defers.length = 0;
107
+ }
59
108
  dispose() {
109
+ this.requireNotExecuting();
60
110
  this._callbacks.length = 0;
61
111
  this.fireNoError =
62
112
  this.fire =
@@ -65,5 +115,10 @@ export class Emitter {
65
115
  throw new Error('Event is disposed');
66
116
  };
67
117
  }
118
+ requireNotExecuting() {
119
+ if (this.executing) {
120
+ throw new Error('conflict state, emitter is firing');
121
+ }
122
+ }
68
123
  }
69
124
  //# sourceMappingURL=event.js.map
@@ -6,5 +6,5 @@
6
6
  "../../../../src/lifecycle/event/event.ts"
7
7
  ],
8
8
  "names": [],
9
- "mappings": "AAUA;;;GAGG;AACH,MAAM,OAAO,OAAO;IACA,UAAU,GAAsB,EAAE,CAAC;IAEtD;QACC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACI,aAAa;QACnB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACI,IAAI,CAAC,IAAO;QAClB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;IACF,CAAC;IAED;;OAEG;IACI,WAAW,CAAC,IAAO;QACzB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,CAAC;gBACJ,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;YACrC,CAAC;QACF,CAAC;IACF,CAAC;IAED;;OAEG;IACH,IAAI,QAAQ;QACX,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,QAAyB;QAC/B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClC,OAAO;YACN,OAAO,EAAE,GAAG,EAAE;gBACb,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAChD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;oBAClB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAClC,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;IAED,OAAO;QACN,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,WAAW;YACf,IAAI,CAAC,IAAI;gBACT,IAAI,CAAC,MAAM;oBACV,GAAG,EAAE;wBACJ,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;oBACtC,CAAC,CAAC;IACL,CAAC;CACD"
9
+ "mappings": "AAYA;;;GAGG;AACH,MAAM,OAAO,OAAO;IACA,UAAU,GAAsB,EAAE,CAAC;IAC9C,SAAS,GAAY,KAAK,CAAC;IAEnC;QACC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACI,aAAa;QACnB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACI,IAAI,CAAC,IAAO;QAClB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC;YACJ,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACxC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;QACF,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACxB,CAAC;IACF,CAAC;IAED;;OAEG;IACI,WAAW,CAAC,IAAO;QACzB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,CAAC;gBACJ,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;YACrC,CAAC;QACF,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,IAAI,QAAQ;QACX,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,QAAyB;QAC/B,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YAC7B,IAAI,CAAC,QAAQ;gBAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,MAAM,WAAW,GAAG,GAAG,EAAE;YACxB,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAChD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBAClB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAClC,CAAC;QACF,CAAC,CAAC;QACF,OAAO;YACN,OAAO,EAAE,GAAG,EAAE;gBACb,QAAQ,GAAG,IAAI,CAAC;gBAChB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACpB,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;gBACzB,CAAC;qBAAM,CAAC;oBACP,WAAW,EAAE,CAAC;gBACf,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,IAAI,CAAC,QAAyB;QAC7B,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YACvC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,UAAU,CAAC,OAAO,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;QACH,OAAO,UAAU,CAAC;IACnB,CAAC;IAEO,MAAM,GAAc,EAAE,CAAC;IACxB,KAAK,CAAC,EAAW;QACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;IACO,OAAO;QACd,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9B,EAAE,EAAE,CAAC;QACN,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,OAAO;QACN,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,WAAW;YACf,IAAI,CAAC,IAAI;gBACT,IAAI,CAAC,MAAM;oBACV,GAAG,EAAE;wBACJ,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;oBACtC,CAAC,CAAC;IACL,CAAC;IAEO,mBAAmB;QAC1B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACtD,CAAC;IACF,CAAC;CACD"
10
10
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@idlebox/common",
3
3
  "type": "module",
4
- "version": "1.4.1",
4
+ "version": "1.4.2",
5
5
  "license": "MIT",
6
6
  "main": "./lib/cjs/__create_index.generated.cjs",
7
7
  "module": "./lib/esm/__create_index.generated.js",
@@ -18,9 +18,9 @@
18
18
  "repository": "https://github.com/GongT/baobao",
19
19
  "devDependencies": {
20
20
  "@rushstack/heft": "^0.68.2",
21
- "@build-script/single-dog-asset": "^1.0.31",
22
- "@idlebox/itypes": "^1.0.5",
23
- "@internal/local-rig": "^1.0.1"
21
+ "@build-script/single-dog-asset": "^1.0.33",
22
+ "@internal/local-rig": "^1.0.1",
23
+ "@idlebox/itypes": "^1.0.5"
24
24
  },
25
25
  "scripts": {
26
26
  "test": "heft test",
@@ -8,12 +8,15 @@ export interface EventRegister<T> {
8
8
  (callback: EventHandler<T>): IDisposable;
9
9
  }
10
10
 
11
+ type DeferFn = () => void;
12
+
11
13
  /**
12
14
  * 事件注册对象
13
15
  * @public
14
16
  */
15
17
  export class Emitter<T> implements IDisposable {
16
18
  protected readonly _callbacks: EventHandler<T>[] = [];
19
+ private executing: boolean = false;
17
20
 
18
21
  constructor() {
19
22
  this.handle = this.handle.bind(this);
@@ -31,8 +34,15 @@ export class Emitter<T> implements IDisposable {
31
34
  * @param data 回调数据
32
35
  */
33
36
  public fire(data: T) {
34
- for (const callback of this._callbacks) {
35
- callback(data);
37
+ this.requireNotExecuting();
38
+ this.executing = true;
39
+ try {
40
+ for (const callback of this._callbacks) {
41
+ callback(data);
42
+ }
43
+ } finally {
44
+ this.doDefer();
45
+ this.executing = false;
36
46
  }
37
47
  }
38
48
 
@@ -40,6 +50,8 @@ export class Emitter<T> implements IDisposable {
40
50
  * 与 `fire()`相同,但是忽略任何错误,并且即便出错也继续执行全部callback
41
51
  */
42
52
  public fireNoError(data: T) {
53
+ this.requireNotExecuting();
54
+ this.executing = true;
43
55
  for (const callback of this._callbacks) {
44
56
  try {
45
57
  callback(data);
@@ -47,6 +59,8 @@ export class Emitter<T> implements IDisposable {
47
59
  console.error('Error ignored: ', e);
48
60
  }
49
61
  }
62
+ this.doDefer();
63
+ this.executing = false;
50
64
  }
51
65
 
52
66
  /**
@@ -61,18 +75,55 @@ export class Emitter<T> implements IDisposable {
61
75
  * @param callback 回调函数
62
76
  */
63
77
  handle(callback: EventHandler<T>): IDisposable {
64
- this._callbacks.unshift(callback);
78
+ this.requireNotExecuting();
79
+ let disposed = false;
80
+ this._callbacks.unshift((e) => {
81
+ if (!disposed) callback(e);
82
+ });
83
+ const realDispose = () => {
84
+ const index = this._callbacks.indexOf(callback);
85
+ if (index !== -1) {
86
+ this._callbacks.splice(index, 1);
87
+ }
88
+ };
65
89
  return {
66
90
  dispose: () => {
67
- const index = this._callbacks.indexOf(callback);
68
- if (index !== -1) {
69
- this._callbacks.splice(index, 1);
91
+ disposed = true;
92
+ if (this.executing) {
93
+ this.defer(realDispose);
94
+ } else {
95
+ realDispose();
70
96
  }
71
97
  },
72
98
  };
73
99
  }
74
100
 
101
+ /**
102
+ * 注册一次性回调
103
+ * @param callback 回调函数
104
+ */
105
+ once(callback: EventHandler<T>): IDisposable {
106
+ this.requireNotExecuting();
107
+ const disposable = this.handle((data) => {
108
+ callback(data);
109
+ disposable.dispose();
110
+ });
111
+ return disposable;
112
+ }
113
+
114
+ private defers: DeferFn[] = [];
115
+ public defer(fn: DeferFn) {
116
+ this.defers.push(fn);
117
+ }
118
+ private doDefer() {
119
+ for (const fn of this.defers) {
120
+ fn();
121
+ }
122
+ this.defers.length = 0;
123
+ }
124
+
75
125
  dispose() {
126
+ this.requireNotExecuting();
76
127
  this._callbacks.length = 0;
77
128
  this.fireNoError =
78
129
  this.fire =
@@ -81,4 +132,10 @@ export class Emitter<T> implements IDisposable {
81
132
  throw new Error('Event is disposed');
82
133
  };
83
134
  }
135
+
136
+ private requireNotExecuting() {
137
+ if (this.executing) {
138
+ throw new Error('conflict state, emitter is firing');
139
+ }
140
+ }
84
141
  }