@zk-tech/bedrock 0.0.1 → 0.1.0
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/dist/async/index.cjs.map +1 -1
- package/dist/async/index.d.cts +2 -2
- package/dist/async/index.d.ts +2 -2
- package/dist/async/index.js.map +1 -1
- package/dist/error/index.cjs.map +1 -1
- package/dist/error/index.d.cts +19 -19
- package/dist/error/index.d.ts +19 -19
- package/dist/error/index.js.map +1 -1
- package/dist/{error-base-B4zaiJ5m.d.cts → error-base-DOFtBFla.d.cts} +8 -8
- package/dist/{error-base-B4zaiJ5m.d.ts → error-base-DOFtBFla.d.ts} +8 -8
- package/dist/promise/index.cjs.map +1 -1
- package/dist/promise/index.d.cts +4 -4
- package/dist/promise/index.d.ts +4 -4
- package/dist/promise/index.js.map +1 -1
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +2 -2
- package/dist/worker/index.d.ts +2 -2
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -2
- package/src/_internal/logger.ts +0 -59
- package/src/array/array.test.ts +0 -35
- package/src/array/array.ts +0 -25
- package/src/array/index.ts +0 -1
- package/src/assert/assert.test.ts +0 -86
- package/src/assert/assert.ts +0 -42
- package/src/assert/index.ts +0 -2
- package/src/async/barrier.test.ts +0 -90
- package/src/async/barrier.ts +0 -58
- package/src/async/cancellation.test.ts +0 -85
- package/src/async/cancellation.ts +0 -193
- package/src/async/index.ts +0 -18
- package/src/async/queue/queue.test.ts +0 -70
- package/src/async/queue/queue.ts +0 -56
- package/src/async/queue/task.test.ts +0 -155
- package/src/async/queue/task.ts +0 -67
- package/src/async/utils.test.ts +0 -28
- package/src/async/utils.ts +0 -8
- package/src/async/wait.ts +0 -9
- package/src/byte/format.test.ts +0 -64
- package/src/byte/format.ts +0 -44
- package/src/byte/index.ts +0 -2
- package/src/byte/node_modules/.vitest/results.json +0 -1
- package/src/byte/var.ts +0 -11
- package/src/cache/index.ts +0 -2
- package/src/cache/lru-with-timeout.test.ts +0 -88
- package/src/cache/lru-with-timeout.ts +0 -85
- package/src/cache/lru.test.ts +0 -56
- package/src/cache/lru.ts +0 -59
- package/src/context/context.test.ts +0 -17
- package/src/context/context.ts +0 -60
- package/src/context/index.ts +0 -8
- package/src/di/base.ts +0 -73
- package/src/di/container-service.test.ts +0 -179
- package/src/di/context.web.tsx +0 -41
- package/src/di/descriptor.ts +0 -31
- package/src/di/idle-value.test.ts +0 -73
- package/src/di/idle-value.ts +0 -63
- package/src/di/index.common.ts +0 -32
- package/src/di/index.ts +0 -2
- package/src/di/instantiation-service.interface.ts +0 -46
- package/src/di/instantiation-service.test.ts +0 -337
- package/src/di/instantiation-service.ts +0 -468
- package/src/di/lazy/foo.mock.ts +0 -28
- package/src/di/lazy/idle-load.ts +0 -39
- package/src/di/lazy/index.ts +0 -4
- package/src/di/lazy/lazy-service.test.ts +0 -65
- package/src/di/lazy/lazy-service.ts +0 -71
- package/src/di/lazy/type.ts +0 -5
- package/src/di/node_modules/.vitest/results.json +0 -1
- package/src/di/proxy-builder.test.ts +0 -45
- package/src/di/proxy-builder.ts +0 -38
- package/src/di/service-collection.test.ts +0 -27
- package/src/di/service-collection.ts +0 -46
- package/src/di/service-ownership-collection.test.ts +0 -39
- package/src/di/service-ownership-collection.ts +0 -38
- package/src/di/service-registry.test.ts +0 -66
- package/src/di/service-registry.ts +0 -99
- package/src/di/trace.ts +0 -85
- package/src/dispose/disposable-store.test.ts +0 -57
- package/src/dispose/disposable-store.ts +0 -80
- package/src/dispose/disposable-t.test.ts +0 -123
- package/src/dispose/disposable-t.ts +0 -238
- package/src/dispose/disposable-utils.test.ts +0 -15
- package/src/dispose/disposable-utils.ts +0 -28
- package/src/dispose/dispose-base.ts +0 -9
- package/src/dispose/index.ts +0 -34
- package/src/dispose/logger.test.ts +0 -65
- package/src/dispose/logger.ts +0 -39
- package/src/dispose/timer.test.ts +0 -30
- package/src/dispose/timer.ts +0 -16
- package/src/dispose/tracker.test.ts +0 -51
- package/src/dispose/tracker.ts +0 -105
- package/src/error/error-base.ts +0 -45
- package/src/error/error-code.ts +0 -39
- package/src/error/error-const.test.ts +0 -30
- package/src/error/error-const.ts +0 -16
- package/src/error/error-or.test.ts +0 -44
- package/src/error/error-or.ts +0 -2
- package/src/error/error-t.test.ts +0 -116
- package/src/error/error-t.ts +0 -100
- package/src/error/index.ts +0 -24
- package/src/error/node_modules/.vitest/results.json +0 -1
- package/src/event/disposable-linked-list.ts +0 -29
- package/src/event/emitter.test.ts +0 -191
- package/src/event/emitter.ts +0 -162
- package/src/event/error-handler.ts +0 -22
- package/src/event/index.ts +0 -34
- package/src/event/once.ts +0 -29
- package/src/event/phase-emitter.test.ts +0 -212
- package/src/event/phase-emitter.ts +0 -209
- package/src/event/shortcut-event-utils.ts +0 -33
- package/src/event/utils.ts +0 -6
- package/src/event/when.ts +0 -40
- package/src/function/debounce.test.ts +0 -274
- package/src/function/debounce.ts +0 -168
- package/src/function/index.ts +0 -2
- package/src/function/node_modules/.vitest/results.json +0 -1
- package/src/function/throttle.test.ts +0 -179
- package/src/function/throttle.ts +0 -26
- package/src/hash/hash-t.test.ts +0 -100
- package/src/hash/hash-t.ts +0 -51
- package/src/hash/index.ts +0 -3
- package/src/json/index.ts +0 -1
- package/src/json/node_modules/.vitest/results.json +0 -1
- package/src/json/parse.ts +0 -19
- package/src/launch/abstract-job.ts +0 -45
- package/src/launch/cost-recorder.ts +0 -22
- package/src/launch/index.ts +0 -2
- package/src/launch/job-scheduler.test.ts +0 -122
- package/src/launch/job-scheduler.ts +0 -118
- package/src/launch/node_modules/.vitest/deps/_metadata.json +0 -8
- package/src/launch/node_modules/.vitest/deps/package.json +0 -3
- package/src/launch/node_modules/.vitest/results.json +0 -1
- package/src/lock/README.md +0 -11
- package/src/lock/capability.test.ts +0 -110
- package/src/lock/capability.ts +0 -89
- package/src/lock/index.ts +0 -15
- package/src/lock/node_modules/.vitest/results.json +0 -1
- package/src/lock/semaphore.ts +0 -21
- package/src/lock/shared-mutex.test.ts +0 -537
- package/src/lock/shared-mutex.ts +0 -242
- package/src/lock/utils.test.ts +0 -165
- package/src/lock/utils.ts +0 -135
- package/src/lodash-es/index.ts +0 -1
- package/src/math/degree.ts +0 -16
- package/src/math/index.ts +0 -7
- package/src/math/math.test.ts +0 -40
- package/src/math/math.ts +0 -64
- package/src/math/node_modules/.vitest/results.json +0 -1
- package/src/math/vector.test.ts +0 -73
- package/src/math/vector.ts +0 -114
- package/src/network/client.interface.ts +0 -104
- package/src/network/client.web.ts +0 -24
- package/src/network/index.common.ts +0 -10
- package/src/network/index.ts +0 -2
- package/src/network/plugins/retry.ts +0 -98
- package/src/objects/deep-clone.test.ts +0 -40
- package/src/objects/deep-clone.ts +0 -13
- package/src/objects/deep-equal.test.ts +0 -86
- package/src/objects/deep-equal.ts +0 -60
- package/src/objects/index.ts +0 -4
- package/src/platform/index.ts +0 -64
- package/src/promise/index.ts +0 -16
- package/src/promise/promise.test.ts +0 -254
- package/src/promise/promise.ts +0 -212
- package/src/scheduler/callback-token.ts +0 -31
- package/src/scheduler/core/actuator-args.test.ts +0 -47
- package/src/scheduler/core/actuator.test.ts +0 -82
- package/src/scheduler/core/actuator.ts +0 -58
- package/src/scheduler/core/chunk-scheduler.test.ts +0 -54
- package/src/scheduler/core/chunk-scheduler.ts +0 -28
- package/src/scheduler/core/node_modules/.vitest/results.json +0 -1
- package/src/scheduler/core/scheduler.test.ts +0 -328
- package/src/scheduler/core/scheduler.ts +0 -172
- package/src/scheduler/core/task-queue.test.ts +0 -78
- package/src/scheduler/core/task-queue.ts +0 -44
- package/src/scheduler/core/task.test.ts +0 -34
- package/src/scheduler/core/task.ts +0 -52
- package/src/scheduler/core/utils.ts +0 -48
- package/src/scheduler/executor/abstract-executor.test.ts +0 -44
- package/src/scheduler/executor/abstract-executor.ts +0 -38
- package/src/scheduler/executor/executor.interface.ts +0 -39
- package/src/scheduler/executor/idle-callback-executor.test.ts +0 -70
- package/src/scheduler/executor/idle-callback-executor.ts +0 -98
- package/src/scheduler/executor/make-executor.ts +0 -18
- package/src/scheduler/executor/post-message-executor.test.ts +0 -66
- package/src/scheduler/executor/post-message-executor.ts +0 -52
- package/src/scheduler/index.ts +0 -15
- package/src/scheduler/lv-scheduler-callback.ts +0 -19
- package/src/scheduler/lv-scheduler-config.ts +0 -17
- package/src/scheduler/type.ts +0 -48
- package/src/sprintf/index.ts +0 -2
- package/src/sprintf/sprintf.test.ts +0 -95
- package/src/sprintf/sprintf.ts +0 -97
- package/src/structure/graph.test.ts +0 -181
- package/src/structure/graph.ts +0 -105
- package/src/structure/index.ts +0 -8
- package/src/structure/linked-list.test.ts +0 -74
- package/src/structure/linked-list.ts +0 -145
- package/src/structure/min-heap.test.ts +0 -71
- package/src/structure/min-heap.ts +0 -91
- package/src/type/REAME.md +0 -2
- package/src/type/distributive-omit.interface.ts +0 -4
- package/src/type/index.ts +0 -3
- package/src/type/object-key-paths.interface.ts +0 -40
- package/src/undo-redo-stack/README.md +0 -61
- package/src/undo-redo-stack/action-stack.test.ts +0 -330
- package/src/undo-redo-stack/action-stack.ts +0 -150
- package/src/undo-redo-stack/element.ts +0 -4
- package/src/undo-redo-stack/index.ts +0 -7
- package/src/undo-redo-stack/state-stack.test.ts +0 -118
- package/src/undo-redo-stack/state-stack.ts +0 -133
- package/src/uuid/index.ts +0 -7
- package/src/uuid/uuid.ts +0 -86
- package/src/worker/cors-worker.ts +0 -38
- package/src/worker/index.ts +0 -4
- package/src/worker/node_modules/.vitest/results.json +0 -1
- package/src/worker/promise-worker-main-thread.test.ts +0 -91
- package/src/worker/promise-worker-main-thread.ts +0 -76
- package/src/worker/promise-worker-worker-thread.ts +0 -64
- package/src/worker/promise-worker.interface.ts +0 -15
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { lvAssert } from '@/assert';
|
|
2
|
-
import { Emitter, type Event, type EmitterOptions } from './emitter';
|
|
3
|
-
import {
|
|
4
|
-
type IMakeShortcutEvent,
|
|
5
|
-
makeSyncShortcutEvent,
|
|
6
|
-
makeAsyncShortcutEvent,
|
|
7
|
-
} from './shortcut-event-utils';
|
|
8
|
-
import type { IDisposable } from '@/dispose';
|
|
9
|
-
import { Logger } from '@/_internal/logger';
|
|
10
|
-
|
|
11
|
-
export interface IPhaseChecker<T> {
|
|
12
|
-
(before: T, after: T): boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function defaultCheck<T>(_before: T, _after: T) {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* WhenPhaseEvent相比较Event有如下特点
|
|
21
|
-
* 1. 增加了callback前第一个参数,可以明确listener对应的phase
|
|
22
|
-
* 2. 会进行状态补发
|
|
23
|
-
*/
|
|
24
|
-
export interface WhenPhaseEvent<T> {
|
|
25
|
-
(phase: T, listener: () => any): IDisposable;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* PhaseEvent相比较Event有如下特点
|
|
30
|
-
* 1. 参数一定为空
|
|
31
|
-
* 2. 会进行状态补发
|
|
32
|
-
*/
|
|
33
|
-
export type PhaseEvent = Event<[]>;
|
|
34
|
-
|
|
35
|
-
interface IPhaseEmitter {
|
|
36
|
-
emitter: Emitter<[]>;
|
|
37
|
-
fn: Event<[]>;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export enum ShortcutEventMode {
|
|
41
|
-
Async,
|
|
42
|
-
Sync,
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface IPhaseEmitterConfig<T> {
|
|
46
|
-
checker?: IPhaseChecker<T>;
|
|
47
|
-
shortcutEventMode?: ShortcutEventMode;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 阶段状态事件触发器,相比较原始的emitter有如下不同
|
|
52
|
-
* 1. 明确了事件类型一定是生命周期的扭转
|
|
53
|
-
* a. 必须传入一个枚举表示阶段状态
|
|
54
|
-
* b. 抛出的事件只能是生命周期扭转,不允许携带参数
|
|
55
|
-
*
|
|
56
|
-
* 2. 当状态已经到达,后监听,进行补发事件
|
|
57
|
-
*
|
|
58
|
-
* -------------------------
|
|
59
|
-
* 注意:由于存在事件补发,所以该事件触发器其实很危险,冲击到了依赖关系
|
|
60
|
-
* 本身A依赖B的某个事件,那么正确的顺序应该是:
|
|
61
|
-
* B模块初始化->A模块初始化->B抛出事件->A监听到事件
|
|
62
|
-
*
|
|
63
|
-
* 但如果存在事件补发,以下流程表面没有问题
|
|
64
|
-
* B模块初始化->B抛出事件->A模块初始化->A监听到事件
|
|
65
|
-
* 实际上可能有两个问题
|
|
66
|
-
* 1. A监听到的事件,并不清楚在A初始化前触发还是初始化后触发,信息丢失
|
|
67
|
-
* 2. B抛出事件,A其实必须要响应,响应晚了其实也是问题
|
|
68
|
-
*
|
|
69
|
-
* 所以事件补发是一件非常危险的事情,不要随意补发。
|
|
70
|
-
* -------------------------
|
|
71
|
-
*
|
|
72
|
-
* 只有状态扭转的事件可以存在合理的补发
|
|
73
|
-
* A监听B的状态变更
|
|
74
|
-
* 一般来说,A模块内代码的写法可能是
|
|
75
|
-
* ```
|
|
76
|
-
* if (B.isReady) {
|
|
77
|
-
* doSomething();
|
|
78
|
-
* } else {
|
|
79
|
-
* B.onReady(doSomething);
|
|
80
|
-
* }
|
|
81
|
-
* ```
|
|
82
|
-
* 这种情况,我们借助事件补发可以变成如下来减少代码量。
|
|
83
|
-
* ```
|
|
84
|
-
* B.onReady(doSomething);
|
|
85
|
-
* ```
|
|
86
|
-
*
|
|
87
|
-
* 最经典的事件补发就是CancellationSourceToken的设计,我们将其抽象出一种通用能力。
|
|
88
|
-
* 使用demo如下:
|
|
89
|
-
* ```
|
|
90
|
-
* enum Phase {
|
|
91
|
-
* Waiting,
|
|
92
|
-
* Eventually,
|
|
93
|
-
* }
|
|
94
|
-
*
|
|
95
|
-
* class Foo {
|
|
96
|
-
* phaseEmitter = new PhaseEmitter<Phase>(Phase.Waiting);
|
|
97
|
-
* // 方式1,监听指定的状态到达
|
|
98
|
-
* // 外部: foo.onEventually(doSomething);
|
|
99
|
-
* onEventually = this.phaseEmitter.when(Phase.Eventually);
|
|
100
|
-
*
|
|
101
|
-
* // 方式2,给予外部更高的自由度
|
|
102
|
-
* // 外部: foo.onPhase(Phase.Eventually, doSomething);
|
|
103
|
-
* onPhase = this.phaseEmitter.whenPhase;
|
|
104
|
-
*
|
|
105
|
-
* // 方式3,监听变更(该方式不会补发)
|
|
106
|
-
* // 外部: foo.onPhaseChange((phase) => doSomething)
|
|
107
|
-
* onPhaseChange = this.phaseEmitter.event;
|
|
108
|
-
* }
|
|
109
|
-
* ```
|
|
110
|
-
* 有问题联系基建侧同学。
|
|
111
|
-
*/
|
|
112
|
-
export class PhaseEmitter<T, K extends T = T> {
|
|
113
|
-
private _globalEmitter?: Emitter<[T]>;
|
|
114
|
-
private readonly _phaseEmitterMap: Map<K, IPhaseEmitter> = new Map();
|
|
115
|
-
private _phaseEvent?: WhenPhaseEvent<T>;
|
|
116
|
-
private readonly _shortcutEvent: IMakeShortcutEvent<T>;
|
|
117
|
-
|
|
118
|
-
constructor(
|
|
119
|
-
private _currentPhase: K,
|
|
120
|
-
config: IPhaseEmitterConfig<T> = {},
|
|
121
|
-
private readonly _phaseChecker: IPhaseChecker<T> = defaultCheck,
|
|
122
|
-
private readonly _options?: EmitterOptions,
|
|
123
|
-
) {
|
|
124
|
-
this._phaseChecker = config.checker ?? defaultCheck;
|
|
125
|
-
|
|
126
|
-
const shortcutEventMode = config.shortcutEventMode ?? ShortcutEventMode.Async;
|
|
127
|
-
this._shortcutEvent =
|
|
128
|
-
shortcutEventMode === ShortcutEventMode.Async ? makeAsyncShortcutEvent : makeSyncShortcutEvent;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
get currentPhase() {
|
|
132
|
-
return this._currentPhase;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
get event(): Event<[T]> {
|
|
136
|
-
if (!this._globalEmitter) {
|
|
137
|
-
this._globalEmitter = new Emitter<T[]>();
|
|
138
|
-
}
|
|
139
|
-
return this._globalEmitter!.event;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
get whenPhase(): WhenPhaseEvent<T> {
|
|
143
|
-
if (this._phaseEvent) {
|
|
144
|
-
return this._phaseEvent;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
this._phaseEvent = (phase: T, listener: () => any) => {
|
|
148
|
-
if (this._currentPhase === phase) {
|
|
149
|
-
return this._shortcutEvent(this._currentPhase)(listener);
|
|
150
|
-
}
|
|
151
|
-
if (!this._phaseEmitterMap.has(phase as K)) {
|
|
152
|
-
this._setPhaseEmitter(phase as K);
|
|
153
|
-
}
|
|
154
|
-
return this._phaseEmitterMap.get(phase as K)!.fn(listener);
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
return this._phaseEvent;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
when(phase: K): PhaseEvent {
|
|
161
|
-
if (this._currentPhase === phase) {
|
|
162
|
-
return this._shortcutEvent(phase);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (!this._phaseEmitterMap.has(phase)) {
|
|
166
|
-
this._setPhaseEmitter(phase);
|
|
167
|
-
}
|
|
168
|
-
return this._phaseEmitterMap.get(phase)!.fn;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
dispose(): void {
|
|
172
|
-
for (const [_phase, emitter] of this._phaseEmitterMap) {
|
|
173
|
-
emitter.emitter.dispose();
|
|
174
|
-
}
|
|
175
|
-
this._globalEmitter?.dispose();
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
setPhase(phase: K): void {
|
|
179
|
-
if (this._currentPhase === phase) {
|
|
180
|
-
Logger.warn(`duplicate set phase: ${phase}.`);
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
lvAssert(this._phaseChecker(this._currentPhase, phase));
|
|
184
|
-
this._currentPhase = phase;
|
|
185
|
-
this._phaseEmitterMap.get(phase)?.emitter.fire();
|
|
186
|
-
this._globalEmitter?.fire(phase);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* 该接口为了和emitter对齐,优先使用setPhase
|
|
191
|
-
* @deprecated 优先使用setPhase,未来可能会去掉
|
|
192
|
-
*/
|
|
193
|
-
fire(phase: K): void {
|
|
194
|
-
this.setPhase(phase);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
private _setPhaseEmitter(phase: K) {
|
|
198
|
-
const emitter = new Emitter<[]>(this._options);
|
|
199
|
-
this._phaseEmitterMap.set(phase, {
|
|
200
|
-
emitter,
|
|
201
|
-
fn: (listener: () => any) => {
|
|
202
|
-
if (this._currentPhase === phase) {
|
|
203
|
-
return this._shortcutEvent(this._currentPhase)(listener);
|
|
204
|
-
}
|
|
205
|
-
return emitter.event(listener);
|
|
206
|
-
},
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { IDisposable } from '@/dispose';
|
|
2
|
-
import type { Event } from './emitter';
|
|
3
|
-
|
|
4
|
-
export interface IMakeShortcutEvent<T> {
|
|
5
|
-
(val: T): Event<[T]>;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function makeSyncShortcutEvent<T>(val: T) {
|
|
9
|
-
return function (callback: (val: T) => void): IDisposable {
|
|
10
|
-
callback(val);
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
dispose() {
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function makeAsyncShortcutEvent<T>(val: T) {
|
|
21
|
-
return function (callback: (val: T) => void): IDisposable {
|
|
22
|
-
const handle = setTimeout(() => {
|
|
23
|
-
callback(val);
|
|
24
|
-
}, 0);
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
dispose() {
|
|
28
|
-
clearTimeout(handle);
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
package/src/event/utils.ts
DELETED
package/src/event/when.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { Event } from './emitter';
|
|
2
|
-
import type { IDisposable } from '@/dispose';
|
|
3
|
-
|
|
4
|
-
// 辅助能力:监听事件,直到事件满足某种状况为止,此时触发 listener callback 并停止监听
|
|
5
|
-
// 类似 MobX 的 `when`
|
|
6
|
-
export function listenWhen<TArgs extends any[]>(
|
|
7
|
-
event: Event<TArgs>,
|
|
8
|
-
predicate: (...args: TArgs) => boolean,
|
|
9
|
-
): Event<TArgs> {
|
|
10
|
-
return (listener, thisArgs = null) => {
|
|
11
|
-
let hasBeenFulfilled = false;
|
|
12
|
-
|
|
13
|
-
// 必须这样写,事件可能同步触发
|
|
14
|
-
// eslint-disable-next-line no-undef-init
|
|
15
|
-
let result: IDisposable | undefined = undefined;
|
|
16
|
-
|
|
17
|
-
result = event((...args) => {
|
|
18
|
-
if (hasBeenFulfilled) {
|
|
19
|
-
result?.dispose();
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// 是否条件满足
|
|
24
|
-
hasBeenFulfilled = predicate(...args);
|
|
25
|
-
|
|
26
|
-
// 如果满足条件则触发回调
|
|
27
|
-
if (hasBeenFulfilled) {
|
|
28
|
-
listener.call(thisArgs, ...args);
|
|
29
|
-
result?.dispose();
|
|
30
|
-
}
|
|
31
|
-
}, null);
|
|
32
|
-
|
|
33
|
-
// 注册事件时可能就会被触发一次?
|
|
34
|
-
if (hasBeenFulfilled) {
|
|
35
|
-
result.dispose();
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return result;
|
|
39
|
-
};
|
|
40
|
-
}
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
/* eslint-disable max-lines-per-function */
|
|
2
|
-
import { sleep } from '../async';
|
|
3
|
-
import { debounce } from './debounce';
|
|
4
|
-
|
|
5
|
-
describe('Debounce', () => {
|
|
6
|
-
test('should debounce a function', async () => {
|
|
7
|
-
let callCount = 0;
|
|
8
|
-
|
|
9
|
-
const debounced = debounce(function (value) {
|
|
10
|
-
++callCount;
|
|
11
|
-
return value;
|
|
12
|
-
}, 32);
|
|
13
|
-
|
|
14
|
-
const results = [debounced('a'), debounced('b'), debounced('c')];
|
|
15
|
-
expect(results).toEqual([undefined, undefined, undefined]);
|
|
16
|
-
expect(callCount).toBe(0);
|
|
17
|
-
|
|
18
|
-
setTimeout(() => {
|
|
19
|
-
expect(callCount).toBe(1);
|
|
20
|
-
|
|
21
|
-
const results = [debounced('d'), debounced('e'), debounced('f')];
|
|
22
|
-
expect(results).toEqual(['c', 'c', 'c']);
|
|
23
|
-
expect(callCount).toBe(1);
|
|
24
|
-
}, 128);
|
|
25
|
-
|
|
26
|
-
await sleep(256);
|
|
27
|
-
expect(callCount).toBe(2);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('subsequent debounced calls return the last func result', async () => {
|
|
31
|
-
const identity = (x: string) => x;
|
|
32
|
-
const debounced = debounce(identity, 32);
|
|
33
|
-
debounced('a');
|
|
34
|
-
|
|
35
|
-
setTimeout(() => {
|
|
36
|
-
expect(debounced('b')).not.toBe('b');
|
|
37
|
-
}, 64);
|
|
38
|
-
|
|
39
|
-
await sleep(128);
|
|
40
|
-
expect(debounced('c')).not.toBe('c');
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('should not immediately call func when wait is 0', async () => {
|
|
44
|
-
let callCount = 0;
|
|
45
|
-
const debounced = debounce(() => {
|
|
46
|
-
++callCount;
|
|
47
|
-
}, 0);
|
|
48
|
-
|
|
49
|
-
debounced();
|
|
50
|
-
debounced();
|
|
51
|
-
expect(callCount).toBe(0);
|
|
52
|
-
|
|
53
|
-
await sleep(5);
|
|
54
|
-
expect(callCount).toBe(1);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test('should apply default options', async () => {
|
|
58
|
-
let callCount = 0;
|
|
59
|
-
const debounced = debounce(
|
|
60
|
-
() => {
|
|
61
|
-
callCount++;
|
|
62
|
-
},
|
|
63
|
-
32,
|
|
64
|
-
{},
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
debounced();
|
|
68
|
-
expect(callCount).toBe(0);
|
|
69
|
-
|
|
70
|
-
await sleep(64);
|
|
71
|
-
expect(callCount).toBe(1);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('should support a leading option', async () => {
|
|
75
|
-
const callCounts = [0, 0];
|
|
76
|
-
|
|
77
|
-
const withLeading = debounce(
|
|
78
|
-
() => {
|
|
79
|
-
callCounts[0]++;
|
|
80
|
-
},
|
|
81
|
-
32,
|
|
82
|
-
{ leading: true },
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
const withLeadingAndTrailing = debounce(
|
|
86
|
-
() => {
|
|
87
|
-
callCounts[1]++;
|
|
88
|
-
},
|
|
89
|
-
32,
|
|
90
|
-
{ leading: true, trailing: true },
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
withLeading();
|
|
94
|
-
expect(callCounts[0]).toBe(1);
|
|
95
|
-
|
|
96
|
-
withLeadingAndTrailing();
|
|
97
|
-
withLeadingAndTrailing();
|
|
98
|
-
expect(callCounts[1]).toBe(1);
|
|
99
|
-
|
|
100
|
-
await sleep(64);
|
|
101
|
-
expect(callCounts).toEqual([1, 2]);
|
|
102
|
-
|
|
103
|
-
withLeading();
|
|
104
|
-
expect(callCounts[0]).toBe(2);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test('subsequent leading debounced calls return the last func result', async () => {
|
|
108
|
-
const debounced = debounce((x: string) => x, 32, { leading: true, trailing: false });
|
|
109
|
-
const results = [debounced('a'), debounced('b')];
|
|
110
|
-
|
|
111
|
-
expect(results).toEqual(['a', 'a']);
|
|
112
|
-
|
|
113
|
-
await sleep(64);
|
|
114
|
-
const results2 = [debounced('c'), debounced('d')];
|
|
115
|
-
expect(results2).toEqual(['c', 'c']);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test('should support a trailing option', async () => {
|
|
119
|
-
let withCount = 0;
|
|
120
|
-
let withoutCount = 0;
|
|
121
|
-
|
|
122
|
-
const withTrailing = debounce(
|
|
123
|
-
() => {
|
|
124
|
-
withCount++;
|
|
125
|
-
},
|
|
126
|
-
32,
|
|
127
|
-
{ trailing: true },
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const withoutTrailing = debounce(
|
|
131
|
-
() => {
|
|
132
|
-
withoutCount++;
|
|
133
|
-
},
|
|
134
|
-
32,
|
|
135
|
-
{ trailing: false },
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
withTrailing();
|
|
139
|
-
expect(withCount).toBe(0);
|
|
140
|
-
|
|
141
|
-
withoutTrailing();
|
|
142
|
-
expect(withoutCount).toBe(0);
|
|
143
|
-
|
|
144
|
-
await sleep(64);
|
|
145
|
-
expect(withCount).toBe(1);
|
|
146
|
-
expect(withoutCount).toBe(0);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test('should support a maxWait option', async () => {
|
|
150
|
-
let callCount = 0;
|
|
151
|
-
|
|
152
|
-
const debounced = debounce(
|
|
153
|
-
() => {
|
|
154
|
-
callCount++;
|
|
155
|
-
},
|
|
156
|
-
32,
|
|
157
|
-
{ maxWait: 64 },
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
debounced();
|
|
161
|
-
debounced();
|
|
162
|
-
expect(callCount).toBe(0);
|
|
163
|
-
|
|
164
|
-
// 超过原来的 maxWait 时间,不足下一个
|
|
165
|
-
await sleep(128);
|
|
166
|
-
expect(callCount).toBe(1); // maxWait 时间后应该调用过一次
|
|
167
|
-
debounced();
|
|
168
|
-
debounced();
|
|
169
|
-
expect(callCount).toBe(1); // 紧接着调用不会立即触发因为还在 maxWait 窗口内
|
|
170
|
-
|
|
171
|
-
// 确保超过第二个 maxWait 时间
|
|
172
|
-
await sleep(128);
|
|
173
|
-
expect(callCount).toBe(2); // 经过足够时间后,第二次 maxWait 达成,调用发生
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test('should support maxWait in a tight loop', async () => {
|
|
177
|
-
const limit = 320;
|
|
178
|
-
let withCount = 0;
|
|
179
|
-
let withoutCount = 0;
|
|
180
|
-
|
|
181
|
-
const withMaxWait = debounce(
|
|
182
|
-
() => {
|
|
183
|
-
withCount++;
|
|
184
|
-
},
|
|
185
|
-
64,
|
|
186
|
-
{ maxWait: 128 },
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
const withoutMaxWait = debounce(() => {
|
|
190
|
-
withoutCount++;
|
|
191
|
-
}, 96);
|
|
192
|
-
|
|
193
|
-
const start = Date.now();
|
|
194
|
-
while (Date.now() - start < limit) {
|
|
195
|
-
withMaxWait();
|
|
196
|
-
withoutMaxWait();
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const actual = [Boolean(withoutCount), Boolean(withCount)];
|
|
200
|
-
await sleep(1);
|
|
201
|
-
expect(actual).toEqual([false, true]);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test('should queue a trailing call for subsequent debounced calls after maxWait', async () => {
|
|
205
|
-
let callCount = 0;
|
|
206
|
-
|
|
207
|
-
const debounced = debounce(
|
|
208
|
-
() => {
|
|
209
|
-
callCount++;
|
|
210
|
-
},
|
|
211
|
-
200,
|
|
212
|
-
{ maxWait: 200 },
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
debounced(); // 第一次立即调用
|
|
216
|
-
|
|
217
|
-
setTimeout(debounced, 190); // 在 maxWait 之前调用
|
|
218
|
-
setTimeout(debounced, 200); // 正在 maxWait 边缘调用
|
|
219
|
-
setTimeout(debounced, 210); // 刚过 maxWait 时调用
|
|
220
|
-
|
|
221
|
-
// 等待足够时间以确保所有的debounce逻辑完成
|
|
222
|
-
await sleep(500);
|
|
223
|
-
expect(callCount).toBe(2); // 预期在 200 ms 后的某个时点触发了第二次调用
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
test('should cancel maxDelayed when delayed is invoked', async () => {
|
|
227
|
-
let callCount = 0;
|
|
228
|
-
|
|
229
|
-
const debounced = debounce(
|
|
230
|
-
() => {
|
|
231
|
-
callCount++;
|
|
232
|
-
},
|
|
233
|
-
32,
|
|
234
|
-
{ maxWait: 64 },
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
debounced(); // 第一次立即调用
|
|
238
|
-
|
|
239
|
-
setTimeout(() => {
|
|
240
|
-
debounced(); // 第二次调用应该重置 maxWait 计时器
|
|
241
|
-
expect(callCount).toBe(1); // 检查到目前为止该函数被调用的次数
|
|
242
|
-
}, 128);
|
|
243
|
-
|
|
244
|
-
// 等待足够时间以确保所有的debounce逻辑完成
|
|
245
|
-
await sleep(256);
|
|
246
|
-
expect(callCount).toBe(2); // 最后,确认函数被调用了两次
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
test('should invoke the trailing call with the correct arguments and this binding', async () => {
|
|
250
|
-
let actual: any;
|
|
251
|
-
let callCount = 0;
|
|
252
|
-
const object = {};
|
|
253
|
-
|
|
254
|
-
const debounced = debounce(
|
|
255
|
-
function (value) {
|
|
256
|
-
actual = [this];
|
|
257
|
-
actual.push(value);
|
|
258
|
-
return ++callCount !== 2;
|
|
259
|
-
},
|
|
260
|
-
32,
|
|
261
|
-
{ leading: true, maxWait: 64 },
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
while (true) {
|
|
265
|
-
if (!debounced.call(object, 'a')) {
|
|
266
|
-
break;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
await sleep(64);
|
|
271
|
-
expect(callCount).toBe(2);
|
|
272
|
-
expect(actual).toEqual([object, 'a']);
|
|
273
|
-
});
|
|
274
|
-
});
|