front-cpu 0.1.1
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/README.md +475 -0
- package/README.zh-CN.md +474 -0
- package/dist/Pipeline.d.ts +119 -0
- package/dist/Pipeline.d.ts.map +1 -0
- package/dist/Pipeline.js +373 -0
- package/dist/Pipeline.js.map +1 -0
- package/dist/debug.d.ts +3 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +12 -0
- package/dist/debug.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +49 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +8 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/isa/index.d.ts +20 -0
- package/dist/isa/index.d.ts.map +1 -0
- package/dist/isa/index.js +26 -0
- package/dist/isa/index.js.map +1 -0
- package/dist/isa/types.d.ts +144 -0
- package/dist/isa/types.d.ts.map +1 -0
- package/dist/isa/types.js +10 -0
- package/dist/isa/types.js.map +1 -0
- package/dist/logging/CPUConsole.d.ts +105 -0
- package/dist/logging/CPUConsole.d.ts.map +1 -0
- package/dist/logging/CPUConsole.js +471 -0
- package/dist/logging/CPUConsole.js.map +1 -0
- package/dist/logging/CPUDebugger.d.ts +91 -0
- package/dist/logging/CPUDebugger.d.ts.map +1 -0
- package/dist/logging/CPUDebugger.js +166 -0
- package/dist/logging/CPUDebugger.js.map +1 -0
- package/dist/logging/CPUEventCollector.d.ts +90 -0
- package/dist/logging/CPUEventCollector.d.ts.map +1 -0
- package/dist/logging/CPUEventCollector.js +353 -0
- package/dist/logging/CPUEventCollector.js.map +1 -0
- package/dist/logging/CPULogger.d.ts +150 -0
- package/dist/logging/CPULogger.d.ts.map +1 -0
- package/dist/logging/CPULogger.js +336 -0
- package/dist/logging/CPULogger.js.map +1 -0
- package/dist/logging/index.d.ts +10 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +16 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/runtime.d.ts +37 -0
- package/dist/logging/runtime.d.ts.map +1 -0
- package/dist/logging/runtime.js +42 -0
- package/dist/logging/runtime.js.map +1 -0
- package/dist/logging/stack-parser.d.ts +22 -0
- package/dist/logging/stack-parser.d.ts.map +1 -0
- package/dist/logging/stack-parser.js +144 -0
- package/dist/logging/stack-parser.js.map +1 -0
- package/dist/logging/types.d.ts +73 -0
- package/dist/logging/types.d.ts.map +1 -0
- package/dist/logging/types.js +47 -0
- package/dist/logging/types.js.map +1 -0
- package/dist/scheduling/ResourceStrategyRegistry.d.ts +61 -0
- package/dist/scheduling/ResourceStrategyRegistry.d.ts.map +1 -0
- package/dist/scheduling/ResourceStrategyRegistry.js +109 -0
- package/dist/scheduling/ResourceStrategyRegistry.js.map +1 -0
- package/dist/scheduling/index.d.ts +6 -0
- package/dist/scheduling/index.d.ts.map +1 -0
- package/dist/scheduling/index.js +5 -0
- package/dist/scheduling/index.js.map +1 -0
- package/dist/scheduling/types.d.ts +44 -0
- package/dist/scheduling/types.d.ts.map +1 -0
- package/dist/scheduling/types.js +5 -0
- package/dist/scheduling/types.js.map +1 -0
- package/dist/stages/EX.d.ts +17 -0
- package/dist/stages/EX.d.ts.map +1 -0
- package/dist/stages/EX.js +95 -0
- package/dist/stages/EX.js.map +1 -0
- package/dist/stages/IF.d.ts +41 -0
- package/dist/stages/IF.d.ts.map +1 -0
- package/dist/stages/IF.js +83 -0
- package/dist/stages/IF.js.map +1 -0
- package/dist/stages/RES.d.ts +17 -0
- package/dist/stages/RES.d.ts.map +1 -0
- package/dist/stages/RES.js +37 -0
- package/dist/stages/RES.js.map +1 -0
- package/dist/stages/SCH.d.ts +77 -0
- package/dist/stages/SCH.d.ts.map +1 -0
- package/dist/stages/SCH.js +270 -0
- package/dist/stages/SCH.js.map +1 -0
- package/dist/stages/WB.d.ts +19 -0
- package/dist/stages/WB.d.ts.map +1 -0
- package/dist/stages/WB.js +102 -0
- package/dist/stages/WB.js.map +1 -0
- package/dist/types.d.ts +111 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +26 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/InstructionCancellation.d.ts +31 -0
- package/dist/utils/InstructionCancellation.d.ts.map +1 -0
- package/dist/utils/InstructionCancellation.js +53 -0
- package/dist/utils/InstructionCancellation.js.map +1 -0
- package/dist/utils/abortable.d.ts +30 -0
- package/dist/utils/abortable.d.ts.map +1 -0
- package/dist/utils/abortable.js +76 -0
- package/dist/utils/abortable.js.map +1 -0
- package/dist/utils/request.d.ts +27 -0
- package/dist/utils/request.d.ts.map +1 -0
- package/dist/utils/request.js +96 -0
- package/dist/utils/request.js.map +1 -0
- package/package.json +74 -0
- package/src/Pipeline.ts +475 -0
- package/src/debug.ts +15 -0
- package/src/index.ts +67 -0
- package/src/interfaces.ts +53 -0
- package/src/isa/index.ts +34 -0
- package/src/isa/types.ts +178 -0
- package/src/logging/CPUConsole.md +843 -0
- package/src/logging/CPUConsole.ts +631 -0
- package/src/logging/CPUDebugger.ts +235 -0
- package/src/logging/CPUEventCollector.ts +418 -0
- package/src/logging/CPULogger.ts +435 -0
- package/src/logging/CPU_LOGGING_DESIGN.md +1319 -0
- package/src/logging/USAGE_GUIDE.md +505 -0
- package/src/logging/index.ts +21 -0
- package/src/logging/runtime.ts +96 -0
- package/src/logging/stack-parser.ts +168 -0
- package/src/logging/types.ts +101 -0
- package/src/scheduling/ResourceStrategyRegistry.ts +124 -0
- package/src/scheduling/index.ts +13 -0
- package/src/scheduling/types.ts +47 -0
- package/src/stages/EX.ts +121 -0
- package/src/stages/IF.ts +103 -0
- package/src/stages/RES.ts +46 -0
- package/src/stages/SCH.ts +331 -0
- package/src/stages/WB.ts +127 -0
- package/src/types.ts +118 -0
- package/src/utils/InstructionCancellation.ts +73 -0
- package/src/utils/abortable.ts +89 -0
- package/src/utils/request.ts +125 -0
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
# FrontCPU
|
|
2
|
+
|
|
3
|
+
## 前端异步的困境
|
|
4
|
+
|
|
5
|
+
每个前端开发者都经历过这些噩梦:
|
|
6
|
+
|
|
7
|
+
**调试地狱**
|
|
8
|
+
```javascript
|
|
9
|
+
// 你的代码里到处都是这种东西
|
|
10
|
+
console.log('开始请求...')
|
|
11
|
+
console.log('请求参数:', params)
|
|
12
|
+
console.log('请求返回:', response)
|
|
13
|
+
console.log('这里执行了吗?')
|
|
14
|
+
console.log('为什么这里没执行???')
|
|
15
|
+
console.log('fuck')
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**竞态条件**
|
|
19
|
+
```javascript
|
|
20
|
+
// 用户快速切换标签页
|
|
21
|
+
fetchTabData('tab1') // 请求发出,耗时 500ms
|
|
22
|
+
fetchTabData('tab2') // 请求发出,耗时 200ms
|
|
23
|
+
fetchTabData('tab3') // 请求发出,耗时 300ms
|
|
24
|
+
// 结果:tab2 的数据先回来,然后 tab3,最后 tab1
|
|
25
|
+
// 用户看到的是 tab1 的数据,但他明明点的是 tab3
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**请求混乱**
|
|
29
|
+
```javascript
|
|
30
|
+
// 同时修改同一条数据
|
|
31
|
+
updateUser({ id: 1, name: 'Alice' }) // 请求 A
|
|
32
|
+
updateUser({ id: 1, name: 'Bob' }) // 请求 B
|
|
33
|
+
// 请求 B 先到达服务器,请求 A 后到达
|
|
34
|
+
// 数据库里是 Alice,但用户以为是 Bob
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**可观测性为零**
|
|
38
|
+
- 请求发出去了吗?
|
|
39
|
+
- 卡在哪个环节?
|
|
40
|
+
- 为什么这个请求比那个慢?
|
|
41
|
+
- 乐观更新回滚了吗?
|
|
42
|
+
- 这个 bug 到底怎么复现?
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 解决方案:像 CPU 一样思考
|
|
47
|
+
|
|
48
|
+
现代 CPU 不会傻傻地一条一条执行指令。它会:
|
|
49
|
+
- 分析指令之间的依赖关系
|
|
50
|
+
- 没有冲突的指令并行执行
|
|
51
|
+
- 有冲突的指令自动排队
|
|
52
|
+
- 全程追踪每条指令的状态
|
|
53
|
+
|
|
54
|
+
**你的前端应用也应该这样。**
|
|
55
|
+
|
|
56
|
+
FrontCPU 将真实 CPU 的乱序执行架构带到前端,让你的异步操作:
|
|
57
|
+
- 自动检测资源冲突
|
|
58
|
+
- 自动决定并行还是串行
|
|
59
|
+
- 自动追踪每个操作的完整生命周期
|
|
60
|
+
- **零代码实现顶级调试体验**
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 调试体验对比
|
|
65
|
+
|
|
66
|
+
### 以前:console.log 地狱
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
async function updateTask(id, data) {
|
|
70
|
+
console.log('[updateTask] 开始', { id, data })
|
|
71
|
+
try {
|
|
72
|
+
console.log('[updateTask] 发送请求...')
|
|
73
|
+
const response = await fetch(`/api/tasks/${id}`, {
|
|
74
|
+
method: 'PUT',
|
|
75
|
+
body: JSON.stringify(data)
|
|
76
|
+
})
|
|
77
|
+
console.log('[updateTask] 响应状态:', response.status)
|
|
78
|
+
const result = await response.json()
|
|
79
|
+
console.log('[updateTask] 返回数据:', result)
|
|
80
|
+
store.tasks[id] = result
|
|
81
|
+
console.log('[updateTask] 状态已更新')
|
|
82
|
+
return result
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error('[updateTask] 失败:', error)
|
|
85
|
+
throw error
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
控制台输出:
|
|
91
|
+
```
|
|
92
|
+
[updateTask] 开始 {id: 1, data: {name: 'test'}}
|
|
93
|
+
[updateTask] 发送请求...
|
|
94
|
+
[updateTask] 响应状态: 200
|
|
95
|
+
[updateTask] 返回数据: {id: 1, name: 'test'}
|
|
96
|
+
[updateTask] 状态已更新
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
问题:
|
|
100
|
+
- 手写大量 log 代码
|
|
101
|
+
- 不知道请求耗时多少
|
|
102
|
+
- 不知道代码从哪里调用的
|
|
103
|
+
- 多个请求的 log 混在一起
|
|
104
|
+
- 上线前还要删掉这些 log
|
|
105
|
+
|
|
106
|
+
### 现在:零代码,顶级调试
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
// 定义指令,一行 log 都不用写
|
|
110
|
+
registerISA({
|
|
111
|
+
'task.update': {
|
|
112
|
+
meta: {
|
|
113
|
+
description: '更新任务',
|
|
114
|
+
resourceIdentifier: (p) => [`task:${p.id}`],
|
|
115
|
+
},
|
|
116
|
+
request: {
|
|
117
|
+
method: 'PUT',
|
|
118
|
+
url: (p) => `/api/tasks/${p.id}`,
|
|
119
|
+
body: (p) => p.data,
|
|
120
|
+
},
|
|
121
|
+
commit: async (result) => {
|
|
122
|
+
store.tasks[result.id] = result
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
// 使用
|
|
128
|
+
pipeline.dispatch('task.update', { id: 1, data: { name: 'test' } })
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
控制台自动输出:
|
|
132
|
+
```
|
|
133
|
+
[指令创建] 14:32:15.123 task.update 📍 src/views/TaskList.vue:42
|
|
134
|
+
├─ Instruction ID: instr-1760629698922-11
|
|
135
|
+
├─ Correlation ID: corr_1760629698922_f_M_sBit6A
|
|
136
|
+
└─ Payload: { id: 1, data: { name: 'test' } }
|
|
137
|
+
|
|
138
|
+
[指令成功] 14:32:15.456 task.update 333ms 📍 src/views/TaskList.vue:42
|
|
139
|
+
├─ 📝 指令参数: { id: 1, data: { name: 'test' } }
|
|
140
|
+
├─ 📥 后端返回: { id: 1, name: 'test', updatedAt: '...' }
|
|
141
|
+
├─ 💾 WB阶段: commit() 执行成功
|
|
142
|
+
└─ 流水线阶段:
|
|
143
|
+
IF→SCH 0ms
|
|
144
|
+
SCH→EX 2ms
|
|
145
|
+
EX→WB ██████ 331ms
|
|
146
|
+
总耗时: 333ms
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**一行调试代码都不用写,自动获得:**
|
|
150
|
+
- 精确到毫秒的时间戳
|
|
151
|
+
- 调用源文件和行号(点击可跳转)
|
|
152
|
+
- 请求参数和返回值
|
|
153
|
+
- 每个流水线阶段的耗时可视化
|
|
154
|
+
- 唯一的指令 ID 和关联 ID(用于追踪)
|
|
155
|
+
|
|
156
|
+
### 失败时自动展开,智能建议
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
[指令失败] 14:32:16.789 task.update 1502ms 📍 src/views/TaskList.vue:42
|
|
160
|
+
├─ 原因: Request timeout
|
|
161
|
+
├─ 📝 指令参数: { id: 1, data: { name: 'test' } }
|
|
162
|
+
├─ 🔄 已回滚乐观更新
|
|
163
|
+
├─ 流水线阶段:
|
|
164
|
+
│ IF→SCH 0ms
|
|
165
|
+
│ SCH→EX 1ms
|
|
166
|
+
│ EX→WB ████████████████████ 1501ms
|
|
167
|
+
│ 总耗时: 1502ms
|
|
168
|
+
├─ 💡 建议:
|
|
169
|
+
│ • 请求超时,考虑增加超时时间或优化后端性能
|
|
170
|
+
│ • 执行耗时 1502ms,超过 1 秒,检查是否存在性能问题
|
|
171
|
+
└─ Error Stack: ...
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 新的开发范式
|
|
177
|
+
|
|
178
|
+
使用 FrontCPU,你只需要做四件事:
|
|
179
|
+
|
|
180
|
+
### 1. UI 层:保持不变
|
|
181
|
+
|
|
182
|
+
你之前用什么框架写 UI,现在就还怎么写。Vue、React、Svelte 都行。
|
|
183
|
+
|
|
184
|
+
```vue
|
|
185
|
+
<template>
|
|
186
|
+
<div v-for="task in tasks" :key="task.id">
|
|
187
|
+
{{ task.name }}
|
|
188
|
+
<button @click="completeTask(task.id)">完成</button>
|
|
189
|
+
</div>
|
|
190
|
+
</template>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 2. 定义指令集
|
|
194
|
+
|
|
195
|
+
声明每个操作:做什么、怎么调接口、怎么更新状态、是否需要排队。
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
registerISA({
|
|
199
|
+
'task.complete': {
|
|
200
|
+
meta: {
|
|
201
|
+
description: '完成任务',
|
|
202
|
+
category: 'task',
|
|
203
|
+
resourceIdentifier: (p) => [`task:${p.id}`], // 资源标识,用于冲突检测
|
|
204
|
+
schedulingStrategy: 'serial', // 同一任务的操作串行执行
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
// 乐观更新:立即显示完成状态
|
|
208
|
+
optimistic: {
|
|
209
|
+
enabled: true,
|
|
210
|
+
apply: (payload) => {
|
|
211
|
+
const task = store.tasks.find(t => t.id === payload.id)
|
|
212
|
+
const snapshot = { ...task }
|
|
213
|
+
task.completed = true
|
|
214
|
+
return snapshot
|
|
215
|
+
},
|
|
216
|
+
rollback: (snapshot) => {
|
|
217
|
+
Object.assign(store.tasks.find(t => t.id === snapshot.id), snapshot)
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
// HTTP 请求
|
|
222
|
+
request: {
|
|
223
|
+
method: 'POST',
|
|
224
|
+
url: (p) => `/api/tasks/${p.id}/complete`,
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
// 服务器确认后更新状态
|
|
228
|
+
commit: async (result, payload) => {
|
|
229
|
+
Object.assign(store.tasks.find(t => t.id === payload.id), result)
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
})
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 3. 组件提交指令
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
function completeTask(id: string) {
|
|
239
|
+
pipeline.dispatch('task.complete', { id })
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
就这样。以下全部自动处理:
|
|
244
|
+
- 指令生命周期追踪(无需手写 log)
|
|
245
|
+
- HTTP 请求发送
|
|
246
|
+
- 请求去重
|
|
247
|
+
- 乐观更新 & 失败回滚
|
|
248
|
+
- 资源冲突检测
|
|
249
|
+
- 并发控制
|
|
250
|
+
|
|
251
|
+
### 4. (可选)注册中断控制器
|
|
252
|
+
|
|
253
|
+
如果你需要处理 SSE、WebSocket、Web Worker 等外部事件:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
pipeline.registerInterruptHandler('sse', {
|
|
257
|
+
onMessage: (event) => {
|
|
258
|
+
// 统一处理所有外部中断
|
|
259
|
+
pipeline.dispatch('data.sync', event.data)
|
|
260
|
+
},
|
|
261
|
+
})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 调度策略
|
|
267
|
+
|
|
268
|
+
不同场景需要不同的并发控制:
|
|
269
|
+
|
|
270
|
+
### out-of-order(默认):最大并行
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// 不同任务可以并行
|
|
274
|
+
pipeline.dispatch('task.fetch', { id: 1 })
|
|
275
|
+
pipeline.dispatch('task.fetch', { id: 2 })
|
|
276
|
+
pipeline.dispatch('task.fetch', { id: 3 })
|
|
277
|
+
// 三个请求同时发出
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### serial:严格串行
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
meta: { schedulingStrategy: 'serial' }
|
|
284
|
+
|
|
285
|
+
// 同一任务的操作必须排队
|
|
286
|
+
pipeline.dispatch('task.update', { id: 1, name: 'A' })
|
|
287
|
+
pipeline.dispatch('task.update', { id: 1, name: 'B' })
|
|
288
|
+
// B 等待 A 完成后才执行,保证顺序
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### latest:只保留最新(搜索场景)
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
meta: { schedulingStrategy: 'latest' }
|
|
295
|
+
|
|
296
|
+
// 用户快速输入
|
|
297
|
+
pipeline.dispatch('search', { query: 'h' })
|
|
298
|
+
pipeline.dispatch('search', { query: 'he' })
|
|
299
|
+
pipeline.dispatch('search', { query: 'hel' })
|
|
300
|
+
pipeline.dispatch('search', { query: 'hello' })
|
|
301
|
+
// 前三个自动取消,只执行 'hello'
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### read-write:读写锁
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
meta: { schedulingStrategy: 'read-write' }
|
|
308
|
+
|
|
309
|
+
// 多个读操作可以并行
|
|
310
|
+
pipeline.dispatch('user.get', { id: 1 })
|
|
311
|
+
pipeline.dispatch('user.get', { id: 1 })
|
|
312
|
+
|
|
313
|
+
// 写操作独占
|
|
314
|
+
pipeline.dispatch('user.update', { id: 1, name: 'test' })
|
|
315
|
+
// 等待所有读完成,阻塞后续读,直到写完成
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 五级流水线架构
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
324
|
+
│ │
|
|
325
|
+
│ dispatch('task.complete', { id: 1 }) │
|
|
326
|
+
│ │ │
|
|
327
|
+
│ ▼ │
|
|
328
|
+
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
|
329
|
+
│ │ IF │ → │ SCH │ → │ EX │ → │ RES │ → │ WB │ │
|
|
330
|
+
│ │ 取指 │ │ 调度 │ │ 执行 │ │ 响应 │ │ 写回 │ │
|
|
331
|
+
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
|
332
|
+
│ │ │ │ │ │ │
|
|
333
|
+
│ 生成ID 检测冲突 执行请求 处理结果 提交状态 │
|
|
334
|
+
│ 捕获调用源 决定并行/等待 乐观更新 错误处理 释放资源 │
|
|
335
|
+
│ 创建取消器 发射指令 超时控制 规范化 回滚(失败) │
|
|
336
|
+
│ │
|
|
337
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## 安装
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
npm install front-cpu
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## 快速开始
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
import { Pipeline, setHttpClient, registerISA } from 'front-cpu'
|
|
352
|
+
|
|
353
|
+
// 1. 配置 HTTP 客户端
|
|
354
|
+
setHttpClient({
|
|
355
|
+
get: (url, config) => fetch(url, config).then(r => r.json()),
|
|
356
|
+
post: (url, data, config) =>
|
|
357
|
+
fetch(url, { method: 'POST', body: JSON.stringify(data), ...config })
|
|
358
|
+
.then(r => r.json()),
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
// 2. 定义指令集
|
|
362
|
+
registerISA({
|
|
363
|
+
'user.fetch': {
|
|
364
|
+
meta: {
|
|
365
|
+
description: '获取用户信息',
|
|
366
|
+
resourceIdentifier: (p) => [`user:${p.id}`],
|
|
367
|
+
},
|
|
368
|
+
request: {
|
|
369
|
+
method: 'GET',
|
|
370
|
+
url: (p) => `/api/users/${p.id}`,
|
|
371
|
+
},
|
|
372
|
+
commit: async (result) => {
|
|
373
|
+
store.user = result
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
// 3. 创建并启动流水线
|
|
379
|
+
const pipeline = new Pipeline({ maxConcurrency: 10 })
|
|
380
|
+
pipeline.start()
|
|
381
|
+
|
|
382
|
+
// 4. 提交指令
|
|
383
|
+
const user = await pipeline.dispatch('user.fetch', { id: 1 })
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## 启用调试(可选)
|
|
387
|
+
|
|
388
|
+
核心包不含调试代码,保持最小体积。需要调试时:
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
import { Pipeline, cpuConsole, ConsoleLevel } from 'front-cpu/debug'
|
|
392
|
+
|
|
393
|
+
// 设置日志级别
|
|
394
|
+
cpuConsole.setLevel(ConsoleLevel.VERBOSE)
|
|
395
|
+
|
|
396
|
+
// 只看特定指令
|
|
397
|
+
cpuConsole.setFilter(['task.update', 'task.complete'])
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
日志级别:
|
|
401
|
+
- `SILENT` - 静默
|
|
402
|
+
- `MINIMAL` - 只显示成功/失败
|
|
403
|
+
- `NORMAL` - 显示关键阶段
|
|
404
|
+
- `VERBOSE` - 显示所有细节 + 流水线耗时图
|
|
405
|
+
- `DEBUG` - 显示完整 payload 和调用栈
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## API 速览
|
|
410
|
+
|
|
411
|
+
### Pipeline
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
const pipeline = new Pipeline({
|
|
415
|
+
maxConcurrency: 10, // 最大并发数
|
|
416
|
+
tickInterval: 16, // 调度器轮询间隔
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
pipeline.start() // 启动
|
|
420
|
+
pipeline.stop() // 暂停
|
|
421
|
+
pipeline.reset() // 重置
|
|
422
|
+
|
|
423
|
+
// 提交指令
|
|
424
|
+
const result = await pipeline.dispatch('type', payload, options)
|
|
425
|
+
|
|
426
|
+
// 取消指令
|
|
427
|
+
pipeline.flush('tag') // 按标签取消
|
|
428
|
+
pipeline.getInstructionsByTags(['tag']) // 按标签查询
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### 指令定义
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
registerISA({
|
|
435
|
+
'instruction.type': {
|
|
436
|
+
meta: {
|
|
437
|
+
description: string,
|
|
438
|
+
category: 'task' | 'debug' | 'schedule' | 'system' | 'area',
|
|
439
|
+
resourceIdentifier: (payload) => string[],
|
|
440
|
+
priority?: number, // 0-10
|
|
441
|
+
timeout?: number, // 毫秒
|
|
442
|
+
schedulingStrategy?: 'out-of-order' | 'serial' | 'latest' | 'read-write',
|
|
443
|
+
},
|
|
444
|
+
|
|
445
|
+
request?: { method, url, body }, // HTTP 请求
|
|
446
|
+
execute?: (payload, context) => any, // 或自定义逻辑
|
|
447
|
+
|
|
448
|
+
optimistic?: { enabled, apply, rollback },
|
|
449
|
+
commit?: (result, payload, context, snapshot) => void,
|
|
450
|
+
},
|
|
451
|
+
})
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## 开发
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
pnpm install # 安装依赖
|
|
460
|
+
pnpm dev # 启动 playground (localhost:3000)
|
|
461
|
+
pnpm build # 构建
|
|
462
|
+
pnpm test # 测试
|
|
463
|
+
pnpm bench # 性能测试
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
## 文档
|
|
467
|
+
|
|
468
|
+
- [API 文档](./docs/API.md)
|
|
469
|
+
- [架构详解](./docs/ARCHITECTURE.md)
|
|
470
|
+
- [指令集开发指南](./docs/ISA_GUIDE.md)
|
|
471
|
+
|
|
472
|
+
## License
|
|
473
|
+
|
|
474
|
+
MIT
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CPU流水线主控制器(解耦版)
|
|
3
|
+
*
|
|
4
|
+
* 通过依赖注入实现零耦合架构
|
|
5
|
+
*/
|
|
6
|
+
import type { QueuedInstruction } from './types';
|
|
7
|
+
import type { IReactiveState } from './interfaces';
|
|
8
|
+
export interface PipelineStatus {
|
|
9
|
+
ifBufferSize: number;
|
|
10
|
+
schPendingSize: number;
|
|
11
|
+
schActiveSize: number;
|
|
12
|
+
totalCompleted: number;
|
|
13
|
+
totalFailed: number;
|
|
14
|
+
totalCancelled: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Pipeline配置
|
|
18
|
+
*/
|
|
19
|
+
export interface PipelineConfig {
|
|
20
|
+
/** Tick间隔(ms),默认16 */
|
|
21
|
+
tickInterval?: number;
|
|
22
|
+
/** 最大并发数,默认10 */
|
|
23
|
+
maxConcurrency?: number;
|
|
24
|
+
/** 响应式状态工厂(用于适配不同框架) */
|
|
25
|
+
reactiveStateFactory?: <T>(initialValue: T) => IReactiveState<T>;
|
|
26
|
+
}
|
|
27
|
+
export declare class Pipeline {
|
|
28
|
+
private IF;
|
|
29
|
+
private SCH;
|
|
30
|
+
private EX;
|
|
31
|
+
private RES;
|
|
32
|
+
private WB;
|
|
33
|
+
private isRunning;
|
|
34
|
+
private tickInterval;
|
|
35
|
+
private readonly TICK_INTERVAL_MS;
|
|
36
|
+
private readonly MAX_CONCURRENCY;
|
|
37
|
+
private totalCompleted;
|
|
38
|
+
private totalFailed;
|
|
39
|
+
private totalCancelled;
|
|
40
|
+
status: IReactiveState<PipelineStatus>;
|
|
41
|
+
private promiseResolvers;
|
|
42
|
+
constructor(config?: PipelineConfig);
|
|
43
|
+
/**
|
|
44
|
+
* 发射指令(外部API)
|
|
45
|
+
*
|
|
46
|
+
* @returns Promise that resolves with the instruction result or rejects with error
|
|
47
|
+
*/
|
|
48
|
+
dispatch<TPayload, TResult = any>(type: string, payload: TPayload, source?: 'user' | 'system' | 'test', options?: {
|
|
49
|
+
tags?: string[];
|
|
50
|
+
}): Promise<TResult>;
|
|
51
|
+
/**
|
|
52
|
+
* 启动流水线
|
|
53
|
+
*/
|
|
54
|
+
start(): void;
|
|
55
|
+
/**
|
|
56
|
+
* 停止流水线
|
|
57
|
+
*/
|
|
58
|
+
stop(): void;
|
|
59
|
+
/**
|
|
60
|
+
* 重置流水线
|
|
61
|
+
*/
|
|
62
|
+
reset(): void;
|
|
63
|
+
/**
|
|
64
|
+
* 处理正在执行的指令
|
|
65
|
+
*/
|
|
66
|
+
private processActiveInstructions;
|
|
67
|
+
/**
|
|
68
|
+
* 处理已取消的指令
|
|
69
|
+
* 直接完成清理工作,不再进入 EX/RES/WB 流程
|
|
70
|
+
*/
|
|
71
|
+
private handleCancelledInstruction;
|
|
72
|
+
/**
|
|
73
|
+
* 执行单个指令
|
|
74
|
+
*/
|
|
75
|
+
private executeInstruction;
|
|
76
|
+
/**
|
|
77
|
+
* 按标签批量取消指令
|
|
78
|
+
* @param tags 要取消的标签(字符串或字符串数组)
|
|
79
|
+
* @returns 取消的指令数量
|
|
80
|
+
*/
|
|
81
|
+
flush(tags: string | string[]): number;
|
|
82
|
+
/**
|
|
83
|
+
* 检查指令是否包含匹配的标签
|
|
84
|
+
*/
|
|
85
|
+
private hasMatchingTags;
|
|
86
|
+
/**
|
|
87
|
+
* 获取带特定标签的指令
|
|
88
|
+
*/
|
|
89
|
+
getInstructionsByTags(tags: string[]): QueuedInstruction[];
|
|
90
|
+
/**
|
|
91
|
+
* 获取所有活跃标签
|
|
92
|
+
*/
|
|
93
|
+
getActiveTags(): string[];
|
|
94
|
+
/**
|
|
95
|
+
* 获取标签统计信息
|
|
96
|
+
*/
|
|
97
|
+
getTagStats(): Record<string, number>;
|
|
98
|
+
/**
|
|
99
|
+
* 更新流水线状态
|
|
100
|
+
*/
|
|
101
|
+
private updateStatus;
|
|
102
|
+
/**
|
|
103
|
+
* 获取流水线状态(供外部使用)
|
|
104
|
+
*/
|
|
105
|
+
getStatus(): PipelineStatus;
|
|
106
|
+
/**
|
|
107
|
+
* 获取IF缓冲区
|
|
108
|
+
*/
|
|
109
|
+
getIFBuffer(): QueuedInstruction[];
|
|
110
|
+
/**
|
|
111
|
+
* 获取SCH pending队列
|
|
112
|
+
*/
|
|
113
|
+
getSCHPendingQueue(): QueuedInstruction[];
|
|
114
|
+
/**
|
|
115
|
+
* 获取SCH active指令
|
|
116
|
+
*/
|
|
117
|
+
getSCHActiveInstructions(): QueuedInstruction[];
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=Pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pipeline.d.ts","sourceRoot":"","sources":["../src/Pipeline.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,sBAAsB;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iBAAiB;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,wBAAwB;IACxB,oBAAoB,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,CAAA;CACjE;AA2BD,qBAAa,QAAQ;IACnB,OAAO,CAAC,EAAE,CAAuB;IACjC,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,GAAG,CAAe;IAC1B,OAAO,CAAC,EAAE,CAAgB;IAE1B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,YAAY,CAA8C;IAClE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IACxC,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,WAAW,CAAI;IACvB,OAAO,CAAC,cAAc,CAAI;IAGnB,MAAM,EAAE,cAAc,CAAC,cAAc,CAAC,CAAA;IAG7C,OAAO,CAAC,gBAAgB,CAMrB;gBAES,MAAM,GAAE,cAAmB;IAwBvC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,GAAG,EAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,QAAQ,EACjB,MAAM,GAAE,MAAM,GAAG,QAAQ,GAAG,MAAe,EAC3C,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAC5B,OAAO,CAAC,OAAO,CAAC;IAuCnB;;OAEG;IACH,KAAK,IAAI,IAAI;IAeb;;OAEG;IACH,IAAI,IAAI,IAAI;IAaZ;;OAEG;IACH,KAAK,IAAI,IAAI;IA6Bb;;OAEG;YACW,yBAAyB;IAqBvC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IA2BlC;;OAEG;YACW,kBAAkB;IA2DhC;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM;IAyBtC;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACH,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE;IAQ1D;;OAEG;IACH,aAAa,IAAI,MAAM,EAAE;IAczB;;OAEG;IACH,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAgBrC;;OAEG;IACH,OAAO,CAAC,YAAY;IAWpB;;OAEG;IACH,SAAS,IAAI,cAAc;IAI3B;;OAEG;IACH,WAAW,IAAI,iBAAiB,EAAE;IAIlC;;OAEG;IACH,kBAAkB,IAAI,iBAAiB,EAAE;IAIzC;;OAEG;IACH,wBAAwB,IAAI,iBAAiB,EAAE;CAGhD"}
|