-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathtopic-cc-loop-lab.html
More file actions
462 lines (442 loc) · 28.9 KB
/
topic-cc-loop-lab.html
File metadata and controls
462 lines (442 loc) · 28.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Loop Lab 仿真大专题 - Everything in Claude-Code</title>
<link rel="stylesheet" href="css/style.css">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🧪</text></svg>">
<meta name="description" content="Loop Lab 仿真大专题:面向 Claude Code / Agent Harness 学习者的生产级教程入口,集中进入 Agent Loop、脚本练习、Trace Prompt、SSE 联调与 Claude Pet SVG 墙。">
<meta name="page:updated" content="2026-05-14">
</head>
<body class="loop-lab-page loop-lab-page--studio">
<nav class="navbar">
<div class="nav-container">
<a href="index.html" class="nav-logo">
<span class="logo-icon">🧪</span>
<span class="logo-text">Loop Lab</span>
</a>
<div class="nav-links">
<a href="#dashboard" class="nav-link">仪表盘</a>
<a href="#choose" class="nav-link">怎么选</a>
<a href="#pages" class="nav-link">仿真器</a>
<a href="#local" class="nav-link">SSE 联调</a>
</div>
<div class="nav-actions">
<button id="theme-toggle" class="theme-toggle" title="切换主题">☀️</button>
<a href="topic-cc-unpacked-zh.html" class="btn-github">CC 解构</a>
<a href="index.html" class="btn-github">首页</a>
</div>
</div>
</nav>
<main class="course-main loop-lab-main">
<div class="container container--layout-wide">
<article class="loop-lab-shell">
<section class="loop-lab-hero loop-lab-hero--studio" aria-labelledby="loop-lab-title">
<div class="loop-lab-hero__copy">
<p class="loop-lab-kicker">Production Tutorial / Agent Simulation Studio</p>
<h1 id="loop-lab-title">把 Agent Loop 从黑箱变成可训练的工作台</h1>
<p class="loop-lab-lede">
这里不是仿真器链接集合,而是一条完整学习路径:先用动态模拟器建立循环直觉,再用脚本练习把命令和配置跑熟,最后用 Trace Prompt 看清一次 Claude Code 请求是如何被拼出来的。
</p>
<div class="loop-lab-actions">
<a href="agent-loop-simulator/" class="btn btn-primary" data-loop-lab-primary-cta>从第一课开始</a>
<a href="#dashboard" class="btn btn-secondary">查看学习仪表盘</a>
</div>
<div class="loop-lab-mode-switch" aria-label="按目标快速进入仿真器">
<a href="agent-loop-simulator/" data-loop-lab-mini="agent-loop">
<span>12 min</span>
<strong>理解循环</strong>
<em data-loop-lab-mini-status>0%</em>
</a>
<a href="agent-script-insight/" data-loop-lab-mini="agent-script">
<span>18 min</span>
<strong>练命令</strong>
<em data-loop-lab-mini-status>0%</em>
</a>
<a href="agent-trace-simulator/" data-loop-lab-mini="agent-trace">
<span>20 min</span>
<strong>拆请求</strong>
<em data-loop-lab-mini-status>0%</em>
</a>
<a href="#local">
<span>10 min</span>
<strong>接事件</strong>
<em>选学</em>
</a>
</div>
<div class="loop-lab-hero-metrics" aria-label="Loop Lab 覆盖范围">
<div><strong>3</strong><span>在线仿真器</span></div>
<div><strong>4</strong><span>机制解释页</span></div>
<div><strong>27</strong><span>SVG 学习角色</span></div>
<div><strong>SSE</strong><span>本地事件流</span></div>
</div>
</div>
<div class="loop-lab-hero__panel" aria-label="仿真专题结构">
<div class="loop-lab-workbench">
<div class="loop-lab-workbench__rail">
<span class="is-active">Loop</span>
<span>Script</span>
<span>Trace</span>
<span>SSE</span>
</div>
<div class="loop-lab-workbench__screen">
<div class="loop-lab-flow-row">
<span>User intent</span>
<i></i>
<span>Model turn</span>
<i></i>
<span>Tool call</span>
</div>
<div class="loop-lab-flow-row loop-lab-flow-row--wide">
<span>Observation</span>
<i></i>
<span>Context repair</span>
<i></i>
<span>Next action</span>
</div>
<div class="loop-lab-workbench__console">
<p><b>trace</b> system + tools + runtime reminder</p>
<p><b>replay</b> prompt → tool_use → tool_result</p>
<p><b>learn</b> choose the smallest useful simulator</p>
</div>
</div>
</div>
</div>
</section>
<nav class="loop-lab-learning-rail" aria-label="Loop Lab 推荐学习路线">
<a href="#dashboard"><span>00</span>看进度</a>
<a href="#choose"><span>01</span>选入口</a>
<a href="#pages"><span>02</span>跑仿真</a>
<a href="#companion"><span>03</span>读机制</a>
<a href="#local"><span>04</span>接事件</a>
</nav>
<section id="dashboard" class="loop-lab-section loop-lab-dashboard" aria-labelledby="loop-lab-dashboard-title" data-loop-lab-dashboard>
<div class="loop-lab-dashboard__head">
<div>
<p class="loop-lab-kicker">Course Dashboard</p>
<h2 id="loop-lab-dashboard-title">你的仿真课程进度</h2>
<p>进度只保存在当前浏览器,用来衔接三台仿真器的阅读、练习和最近学习状态。</p>
</div>
<div class="loop-lab-dashboard__actions">
<a href="agent-loop-simulator/" class="loop-lab-inline-button" data-loop-lab-next-link>继续:理解循环</a>
<button type="button" class="loop-lab-inline-button loop-lab-inline-button--quiet" data-loop-lab-reset>重置本机记录</button>
</div>
</div>
<div class="loop-lab-dashboard__grid">
<div class="loop-lab-progress-gauge" data-loop-lab-ring aria-label="课程总完成率">
<span data-loop-lab-total>0%</span>
<small>总完成率</small>
</div>
<div class="loop-lab-dashboard__stats" aria-label="学习状态摘要">
<div><span>完成课程</span><strong data-loop-lab-complete>0 / 3</strong></div>
<div><span>最近学习</span><strong data-loop-lab-last>还没有开始</strong></div>
<div><span>推荐下一课</span><strong data-loop-lab-next>理解循环 · Agent Loop</strong></div>
</div>
</div>
<div class="loop-lab-learning-summary" data-loop-lab-learning-summary aria-label="本地学习管理筛选"></div>
<div class="loop-lab-data-manager" data-loop-lab-data-manager aria-label="学习数据导出与导入"></div>
<div class="loop-lab-lesson-list" data-loop-lab-lessons aria-label="三段仿真课程进度"></div>
</section>
<section id="choose" class="loop-lab-section loop-lab-section--dense">
<div class="loop-lab-section__head">
<p class="loop-lab-kicker">Decision Guide</p>
<h2>先按问题选入口</h2>
<p>生产级教程最重要的不是把内容堆满,而是让学习者在 10 秒内知道自己该点哪里。</p>
</div>
<div class="loop-lab-choice-grid">
<a href="agent-loop-simulator/" class="loop-lab-choice">
<span>我还不理解循环</span>
<h3>从 Agent Loop 动态模拟器开始</h3>
<p>看一次完整 turn 如何走过模型、工具、观察和最终回答,先建立运行直觉。</p>
</a>
<a href="agent-script-insight/" class="loop-lab-choice">
<span>我想练命令和配置</span>
<h3>进入脚本启示仿真器</h3>
<p>把命令脚本、终端练习、配置生成和测验串成一条可重复训练路径。</p>
</a>
<a href="agent-trace-simulator/" class="loop-lab-choice">
<span>我想拆请求体</span>
<h3>进入 Trace Prompt 仿真器</h3>
<p>对照真实 trace,看 system、tool catalog、runtime reminder 与用户输入如何累计。</p>
</a>
<a href="#local" class="loop-lab-choice">
<span>我想接真实事件</span>
<h3>看本地 SSE 联调</h3>
<p>启动 relay,把演示事件流接到浏览器里,理解仿真与真实运行时之间的接口。</p>
</a>
</div>
</section>
<section id="pets" class="loop-lab-section loop-lab-pet-wall" aria-labelledby="pet-wall-title">
<div class="loop-lab-section__head">
<p class="loop-lab-kicker">Claude Pet SVG Wall</p>
<h2 id="pet-wall-title">一面会让教程有记忆点的 SVG 角色墙</h2>
<p>这些 pixel-style SVG 来自本地 `claude-pets-svg` 素材,放进 Loop Lab 后可以作为章节角色、状态徽章或学习路径视觉资产。</p>
</div>
<div class="loop-lab-pet-wall__toolbar">
<p>默认展示精选角色,展开后查看完整素材墙,避免移动端滚动负担过重。</p>
<button type="button" id="toggle-pet-wall" class="loop-lab-inline-button" aria-expanded="false">展开全部 27 个</button>
</div>
<div class="loop-lab-pets" id="loop-lab-pets" aria-label="Claude Pet SVG wall" data-expanded="false">
<figure><img src="images/claude-pets/claude-pet-happy.svg" alt="Happy Claude pet"><figcaption>Happy</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-coder.svg" alt="Coder Claude pet"><figcaption>Coder</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-wizard.svg" alt="Wizard Claude pet"><figcaption>Wizard</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-scientist.svg" alt="Scientist Claude pet"><figcaption>Scientist</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-detective.svg" alt="Detective Claude pet"><figcaption>Detective</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-rocket.svg" alt="Rocket Claude pet"><figcaption>Rocket</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-astronaut.svg" alt="Astronaut Claude pet"><figcaption>Astronaut</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-explorer.svg" alt="Explorer Claude pet"><figcaption>Explorer</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-artist.svg" alt="Artist Claude pet"><figcaption>Artist</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-mechanic.svg" alt="Mechanic Claude pet"><figcaption>Mechanic</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-teacher.svg" alt="Teacher Claude pet"><figcaption>Teacher</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-coffee.svg" alt="Coffee Claude pet"><figcaption>Coffee</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-mail.svg" alt="Mail Claude pet"><figcaption>Mail</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-music.svg" alt="Music Claude pet"><figcaption>Music</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-gamer.svg" alt="Gamer Claude pet"><figcaption>Gamer</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-chef.svg" alt="Chef Claude pet"><figcaption>Chef</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-ninja.svg" alt="Ninja Claude pet"><figcaption>Ninja</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-pirate.svg" alt="Pirate Claude pet"><figcaption>Pirate</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-raincoat.svg" alt="Raincoat Claude pet"><figcaption>Raincoat</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-winter.svg" alt="Winter Claude pet"><figcaption>Winter</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-party.svg" alt="Party Claude pet"><figcaption>Party</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-crown.svg" alt="Crown Claude pet"><figcaption>Crown</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-heart.svg" alt="Heart Claude pet"><figcaption>Heart</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-skater.svg" alt="Skater Claude pet"><figcaption>Skater</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-sleepy.svg" alt="Sleepy Claude pet"><figcaption>Sleepy</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-blush.svg" alt="Blush Claude pet"><figcaption>Blush</figcaption></figure>
<figure><img src="images/claude-pets/claude-pet-ghost.svg" alt="Ghost Claude pet"><figcaption>Ghost</figcaption></figure>
</div>
</section>
<section id="pages" class="loop-lab-section">
<div class="loop-lab-section__head">
<p class="loop-lab-kicker">Simulation Paths</p>
<h2>三种在线仿真器</h2>
<p>每个入口都对应一种认知负载:先看循环,再练脚本,最后拆 prompt 请求。</p>
</div>
<div class="loop-lab-path-grid loop-lab-path-grid--studio">
<a href="agent-loop-simulator/" class="loop-lab-path loop-lab-path--loop">
<span class="loop-lab-path__num">01</span>
<span class="loop-lab-path__eyebrow">Agent Loop</span>
<h3>动态模拟器</h3>
<p>12 步回放一次完整 Agent 循环,适合第一次建立“模型为什么会调用工具、工具结果如何回灌”的直觉。</p>
<span class="loop-lab-path__meta">输出:运行链路心智图</span>
<strong>进入模拟器 →</strong>
</a>
<a href="agent-script-insight/" class="loop-lab-path loop-lab-path--script">
<span class="loop-lab-path__num">02</span>
<span class="loop-lab-path__eyebrow">Script Insight</span>
<h3>脚本启示仿真器</h3>
<p>把命令脚本、终端练习、配置生成和测验放进一个交互实验室,适合课程训练和 workshop。</p>
<span class="loop-lab-path__meta">输出:可练习的命令套路</span>
<strong>进入练习室 →</strong>
</a>
<a href="agent-trace-simulator/" class="loop-lab-path loop-lab-path--trace">
<span class="loop-lab-path__num">03</span>
<span class="loop-lab-path__eyebrow">Trace Prompt</span>
<h3>Prompt 请求仿真器</h3>
<p>结合三份 cc-route trace,逐层拆解 system、tools、runtime reminder 与用户输入如何组装成请求。</p>
<span class="loop-lab-path__meta">输出:prompt 结构阅读能力</span>
<strong>进入拆解台 →</strong>
</a>
</div>
</section>
<section class="loop-lab-section loop-lab-runway">
<div class="loop-lab-section__head">
<p class="loop-lab-kicker">Learning Runway</p>
<h2>建议按这条路线学</h2>
<p>这个顺序能让概念、操作和源码之间互相托住,不会一下子掉进细节里。</p>
</div>
<div class="loop-lab-runway__grid">
<div><span>Step 1</span><strong>看循环</strong><p>用 Agent Loop 模拟器跑一遍完整 turn。</p></div>
<div><span>Step 2</span><strong>做练习</strong><p>用 Script Insight 把命令、配置、测验跑起来。</p></div>
<div><span>Step 3</span><strong>拆请求</strong><p>用 Trace Prompt 读懂真实请求里的层级。</p></div>
<div><span>Step 4</span><strong>接事件</strong><p>用 SSE 联调理解仿真和真实运行时的接口。</p></div>
</div>
</section>
<section id="companion" class="loop-lab-section loop-lab-section--split">
<div class="loop-lab-section__head">
<p class="loop-lab-kicker">Mechanism Pages</p>
<h2>配套机制页</h2>
<p>这些页面补足控制台、任务状态、Loop 机制和连接器运行时,让仿真不只停留在视觉层。</p>
</div>
<div class="loop-lab-companion-grid">
<a href="topic-codex-loop-console.html" class="loop-lab-mini-card">
<span>控制台视角</span>
<h3>Codex Loop Console</h3>
<p>观察事件、状态与控制台视角,和仿真器形成“可视化 + 控制台”的互补阅读。</p>
</a>
<a href="topic-loop-task-board.html" class="loop-lab-mini-card">
<span>任务状态</span>
<h3>任务驱动舱</h3>
<p>从任务、进度、待发布视角理解本地工作台如何承接 Agent Loop 的长任务状态。</p>
</a>
<a href="topic-loop-mechanisms.html" class="loop-lab-mini-card">
<span>机制抽象</span>
<h3>Loop 机制</h3>
<p>把循环控制、上下文治理、工具调用和停止条件抽成仿真器背后的结构说明。</p>
</a>
<a href="topic-connector-runtime-daemon.html" class="loop-lab-mini-card">
<span>外部接入</span>
<h3>Connector Runtime</h3>
<p>把外部连接器、后台守护进程和 WeChat bind 等接入能力放回运行时分层。</p>
</a>
</div>
</section>
<section id="local" class="loop-lab-section loop-lab-local">
<div class="loop-lab-section__head">
<p class="loop-lab-kicker">Local Event Stream</p>
<h2>本地 SSE 联调</h2>
<p>GitHub Pages 只能展示静态页面;要接事件流,需要在本机启动 relay,再让浏览器订阅 `127.0.0.1`。</p>
</div>
<div class="loop-lab-local__grid">
<div class="loop-lab-command-stack" aria-label="本地联调命令">
<div class="loop-lab-command">
<span>Terminal A</span>
<code>python tools/cc_loop_sse_relay.py --fast</code>
<button type="button" data-copy="python tools/cc_loop_sse_relay.py --fast">复制</button>
</div>
<div class="loop-lab-command">
<span>Terminal B</span>
<code>cd site && python -m http.server 8080</code>
<button type="button" data-copy="cd site && python -m http.server 8080">复制</button>
</div>
<div class="loop-lab-command">
<span>Browser</span>
<code>http://127.0.0.1:8080/topic-cc-loop-lab.html</code>
<button type="button" data-copy="http://127.0.0.1:8080/topic-cc-loop-lab.html">复制</button>
</div>
</div>
<div class="loop-lab-sse-card">
<div class="loop-lab-sse-card__top">
<div>
<label for="sse-url">SSE URL</label>
<p>默认连接本机演示 relay。</p>
</div>
<span id="sse-status" class="loop-lab-status" aria-live="polite">未连接</span>
</div>
<input id="sse-url" type="url" value="http://127.0.0.1:8769/events" size="48" class="search-input cc-loop-lab-url-input">
<div class="loop-lab-sse-actions">
<button type="button" id="btn-connect" class="btn btn-primary">连接</button>
<button type="button" id="btn-close" class="btn btn-secondary cc-loop-lab-close-btn">断开</button>
<button type="button" id="btn-sample" class="btn btn-secondary">填充示例日志</button>
<button type="button" id="btn-clear-log" class="btn btn-secondary">清空日志</button>
</div>
<pre id="sse-log" class="cc-loop-lab-log cc-loop-lab-log-panel" aria-label="SSE 事件日志"></pre>
</div>
</div>
</section>
</article>
</div>
</main>
<footer class="footer">
<div class="container">
<p class="md-source-link"><a href="https://github.com/Harzva/learn-likecc/blob/main/site/md/topic-cc-loop-lab.md" target="_blank" rel="noopener noreferrer">📝 本站页的 Markdown 源文件(GitHub)</a></p>
<p>© 2026 Everything in Claude-Code. 仅供学习研究使用。</p>
</div>
</footer>
<script src="js/app.js"></script>
<script src="simulator-course-system.js"></script>
<script>
(function () {
var urlIn = document.getElementById('sse-url')
var logEl = document.getElementById('sse-log')
var statusEl = document.getElementById('sse-status')
var btnC = document.getElementById('btn-connect')
var btnX = document.getElementById('btn-close')
var btnSample = document.getElementById('btn-sample')
var btnClear = document.getElementById('btn-clear-log')
var petWall = document.getElementById('loop-lab-pets')
var petToggle = document.getElementById('toggle-pet-wall')
var es = null
var sampleEvents = [
'{"stage":"plan","title":"读取任务计划","detail":"Loop Lab 选择本轮最小可验证任务"}',
'{"stage":"tool_use","title":"执行校验","detail":"python tools/check_site_md_parity.py"}',
'{"stage":"observe","title":"回灌结果","detail":"把校验输出转成下一步行动"}',
'{"stage":"handoff","title":"写入下一轮上下文","detail":"生成 evolution note 与待办"}'
]
function line(s) {
if (!logEl) return
logEl.textContent += s + '\n'
logEl.scrollTop = logEl.scrollHeight
}
function setStatus(text, mode) {
if (!statusEl) return
statusEl.textContent = text
statusEl.dataset.mode = mode || 'idle'
}
function closeEs() {
if (es) {
es.close()
es = null
}
setStatus('已断开', 'idle')
}
document.addEventListener('click', function (event) {
var target = event.target.closest('[data-copy]')
if (!target) return
var text = target.getAttribute('data-copy') || ''
if (!navigator.clipboard) return
navigator.clipboard.writeText(text).then(function () {
target.textContent = '已复制'
window.setTimeout(function () { target.textContent = '复制' }, 1100)
})
})
if (petWall && petToggle) {
petToggle.addEventListener('click', function () {
var expanded = petWall.getAttribute('data-expanded') === 'true'
petWall.setAttribute('data-expanded', expanded ? 'false' : 'true')
petToggle.setAttribute('aria-expanded', expanded ? 'false' : 'true')
petToggle.textContent = expanded ? '展开全部 27 个' : '收起素材墙'
})
}
btnX.addEventListener('click', closeEs)
btnClear.addEventListener('click', function () {
logEl.textContent = ''
setStatus('日志已清空', 'idle')
})
btnSample.addEventListener('click', function () {
logEl.textContent = ''
sampleEvents.forEach(line)
setStatus('示例日志', 'sample')
})
btnC.addEventListener('click', function () {
closeEs()
logEl.textContent = ''
var u = (urlIn.value || '').trim()
if (!u) {
setStatus('请填写 URL', 'error')
return
}
if (!window.EventSource) {
setStatus('浏览器不支持 EventSource', 'error')
line('当前浏览器不支持 EventSource,请换现代浏览器或使用示例日志。')
return
}
setStatus('连接中', 'pending')
try {
es = new EventSource(u)
} catch (e) {
setStatus('无法创建 EventSource', 'error')
line(String(e))
return
}
es.onopen = function () {
setStatus('已连接', 'ok')
}
es.onmessage = function (ev) {
setStatus('收到事件', 'ok')
line(ev.data)
}
es.onerror = function () {
if (es && es.readyState === EventSource.CLOSED) {
setStatus('连接已关闭', 'error')
} else {
setStatus('连接错误', 'error')
}
}
})
sampleEvents.forEach(line)
})()
</script>
</body>
</html>