From 5e185c53e3ec449870c8b1f2b99c93e710a5eff2 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Thu, 5 Nov 2026 00:53:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=87=E4=BB=BD=E8=AF=AD=E8=A8=80=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E3=80=81=E9=A1=B6=E7=BA=A7=E7=B1=BB=E5=9E=8B=E4=B8=8E?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E8=AE=BE=E8=AE=A1=E8=8D=89=E7=A8=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Programming Language.md | 4 + README.md | 19 +- appendices/code-storage-and-views.md | 6 +- appendices/formal-grammar.md | 10 +- appendices/framework-runtime-lifecycles.md | 468 +++++++ appendices/glossary.md | 20 +- appendices/language-keywords.md | 1199 ++++++++++++++++++ appendices/language-runtime-lifecycles.md | 384 ++++++ appendices/specification-status.md | 105 +- authoring/references/language-map.md | 4 + guide/01-overview.md | 8 +- guide/02-user-identity.md | 6 +- guide/03-namespaces.md | 8 +- guide/04-program-structure.md | 10 +- guide/05-preflight-and-inflight.md | 4 +- guide/06-lexical-structure.md | 18 +- guide/07-top-level-types/README.md | 189 +++ guide/07-top-level-types/agents.md | 105 ++ guide/07-top-level-types/collections.md | 178 +++ guide/07-top-level-types/definitions.md | 151 +++ guide/07-top-level-types/execution.md | 154 +++ guide/07-top-level-types/functions.md | 142 +++ guide/07-top-level-types/references.md | 125 ++ guide/07-top-level-types/values.md | 131 ++ guide/07-types-and-classes.md | 18 +- guide/08-expressions-and-bindings.md | 4 +- guide/09-functions-and-calls.md | 4 +- guide/10-data-access.md | 2 +- guide/11-resource-access-and-presentation.md | 67 +- guide/13-agents.md | 6 +- guide/14-repl.md | 109 ++ 31 files changed, 3594 insertions(+), 64 deletions(-) create mode 100644 Programming Language.md create mode 100644 appendices/framework-runtime-lifecycles.md create mode 100644 appendices/language-keywords.md create mode 100644 appendices/language-runtime-lifecycles.md create mode 100644 guide/07-top-level-types/README.md create mode 100644 guide/07-top-level-types/agents.md create mode 100644 guide/07-top-level-types/collections.md create mode 100644 guide/07-top-level-types/definitions.md create mode 100644 guide/07-top-level-types/execution.md create mode 100644 guide/07-top-level-types/functions.md create mode 100644 guide/07-top-level-types/references.md create mode 100644 guide/07-top-level-types/values.md create mode 100644 guide/14-repl.md diff --git a/Programming Language.md b/Programming Language.md new file mode 100644 index 0000000..637f5ab --- /dev/null +++ b/Programming Language.md @@ -0,0 +1,4 @@ + + +RenderObject +- \ No newline at end of file diff --git a/README.md b/README.md index b653236..361b8a3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Endorphin 语言文档 -Endorphin 是一门面向云原生应用的编程语言,使用统一的资源与语言模型描述前端界面、数据结构、后端逻辑和 agent。基础内容由平台管理,变量引用资源,开发者和 agent 编写声明、表达式与调用关系,平台解释执行代码,客户端根据资源或结果的类型呈现内容。 +Endorphin 是一门面向云原生应用的编程语言,使用统一的对象与资源模型描述前端界面、数据结构、后端逻辑和 agent。类型本身也是对象,Object 与 Type 构成实例化和继承的基础闭环。平台按具体类型管理对象的生命周期,变量引用资源,开发者和 agent 组织对象、表达式与调用关系,客户端根据资源或结果的类型呈现内容。 ## 阅读指南 正文按概念的依赖顺序编排。首次阅读从第 1 章开始;查询具体写法时,可以直接进入相应章节。每章包含概念定义、语法、示例和行为说明。 -本书为语言设计稿。资源归属 workspace,key 使用 workspace handle 与 namespace 路径;用户以成员角色参与协作。use 形式、整体授权边界和阶段命名等基础约定已经确定。权限操作区分资源编辑与程序使用,函数、类型、数据读取与 UI 的具体写法以本文收录的草案为准。各主题的确定程度统一记录在[规范状态](appendices/specification-status.md),正文不反复叙述设计过程。 +本书为语言设计稿。资源归属 workspace,key 使用 workspace handle 与 namespace 路径;用户以成员角色参与协作。权限操作区分资源编辑与程序使用,函数、类型、数据读取与 UI 的具体写法按所标注的设计状态使用。各主题的确定程度记录在[规范状态](appendices/specification-status.md)。 ## 正文 @@ -21,16 +21,17 @@ Endorphin 是一门面向云原生应用的编程语言,使用统一的资源 ### 第二部分:基础语法 6. [词法结构](guide/06-lexical-structure.md) — 标识符、字面量、符号、标点和注释。 -7. [资源、类型与类](guide/07-types-and-classes.md) — 基础常量、统一数值、媒体归一化、类型与 class。 +7. [资源、类型与类](guide/07-types-and-classes.md) — 类型与实例、资源 atom、具体类型与 class;[Object 与类型系统](guide/07-top-level-types/README.md)解释 Object/Type 闭环、实例化线、继承线及资源 ID。 8. [表达式与绑定](guide/08-expressions-and-bindings.md) — 求值、运算、成员访问、let 与可变资源引用。 9. [函数与调用](guide/09-functions-and-calls.md) — 函数声明、返回值和跨 namespace 组合。 ### 第三部分:应用用法 10. [数据读取](guide/10-data-access.md) — 通过类型取得数据及结果状态。 -11. [资源访问与呈现](guide/11-resource-access-and-presentation.md) — 查看函数、参数就绪、调用结果与按类型呈现。 +11. [资源访问与呈现](guide/11-resource-access-and-presentation.md) — 查看与调用、按类型呈现,以及平台对象、本地副本与跨端同步。 12. [UI 组件](guide/12-ui-components.md) — Column、Row、Spacer 和 Text 的参数与效果。 13. [Agent](guide/13-agents.md) — 共有成员、tools、memory、state、路由、中断与上下文管理。 +14. [交互式会话(REPL)](guide/14-repl.md) — 会话上下文、输入求值、对象查看与远程状态的设计提案。 ## 附录 @@ -40,13 +41,21 @@ Endorphin 是一门面向云原生应用的编程语言,使用统一的资源 - [应用领域](appendices/application-domains.md) — UI、业务逻辑、数据访问和 Agent 的适用范围。 - [规范状态](appendices/specification-status.md) — 已确定约定、语法提案及未定义的边界。 +### 补充参考 + +- [其他语言的关键词分类与逐词说明](appendices/language-keywords.md) — Python、JavaScript、TypeScript、Java、C、C++、C#、Go、Rust、Swift、Kotlin、Julia 的关键词用途与区别,供跨语言学习和设计比较查阅。 +- [12 门语言的执行模型与生命周期](appendices/language-runtime-lifecycles.md) — 逐门比较执行入口、定义与上下文、任务调度、等待恢复及资源清理。 +- [框架如何接管代码执行](appendices/framework-runtime-lifecycles.md) — 从具体动作追踪普通进程、FastAPI、Spring Boot、Unity、React 与 Node/Chromium,并整理 Endorphin 执行模型的研究维度。 + +比较执行机制时,先阅读统一分析模板,再从熟悉的语言进入对应框架案例;这些外部机制不自动成为 Endorphin 的语言规则。 + ## 记法 源码以 `endorphin` 代码块展示,文法以 `ebnf` 代码块展示。源码中的关键字和名称区分大小写;语言阶段名称固定为 `Preflight` 和 `inflight`。 “代码归属”写在代码块之前,用于说明外部上下文,不属于源码。函数体片段会注明使用位置,资源访问与界面结构示意使用 `text` 代码块,不表示新增源码语法。示例中的用户和 namespace 为示意名称。 -正文的函数示例围绕商品定价展开:`atelier:shop.pricing` 提供定价逻辑,`market:shop.checkout` 组合它,`market:shop.ui` 表达界面;数据读取示例使用 `atelier:shop.data`。atelier 与 market 是 workspace handle,后面的路径表示代码组织,不指定执行位置。 +函数示例围绕商品定价展开:`atelier:shop.pricing` 提供定价逻辑,`market:shop.checkout` 组合它,`market:shop.ui` 表达界面;数据读取示例使用 `atelier:shop.data`。atelier 与 market 是 workspace handle,后面的路径表示代码组织,不指定执行位置。 ## 文档维护入口 diff --git a/appendices/code-storage-and-views.md b/appendices/code-storage-and-views.md index 0aa6d58..6791f2a 100644 --- a/appendices/code-storage-and-views.md +++ b/appendices/code-storage-and-views.md @@ -4,7 +4,9 @@ ## 独立代码段 -代码分别存储为独立代码段,每段关联一个归属 workspace 和至少一级 namespace。S3 承担代码内容的存储职责,索引维护 namespace key 与代码段的成员关系;编写或修改代码的用户身份另行记录。 +代码分别存储为独立代码段,以资源 ID 识别并关联归属 workspace。S3 承担代码内容的存储职责,索引维护 namespace key 与代码段的成员关系;一段代码可以具有多个命名入口,编写或修改代码的用户身份另行记录。 + +移除 namespace 成员入口不删除仍被其他保留程序引用的代码段。资源 ID、存储对象键与 namespace key 分别表达逻辑身份、存储位置和命名入口,具体引用语义见[资源引用](../guide/07-top-level-types/references.md)。 源码文件不作为代码身份或 module 边界。本书中的 Markdown 文件是文档章节,不对应语言中的源码组织单位。 @@ -31,7 +33,7 @@ S3 对象键不是语言中的 namespace key。bucket 名、对象键和存储 ## namespace 制 -namespace 同时表达归属与查找位置,使业务函数、类型、界面逻辑和 agent 定义遵循一致的组织模型。第一级与后续层级具有相同语义。 +namespace 提供归属 workspace 内的组织与查找位置,使业务函数、类型、界面逻辑和 agent 定义遵循一致的组织模型。第一级与后续层级具有相同语义。 基础内容也纳入资源归属方向,但本附录的 S3 代码段约定不自动规定媒体、GIS 数据、对象或 agent 记忆的存储后端。代码视图与完整资源集合的区别见[namespace](../guide/03-namespaces.md)。 diff --git a/appendices/formal-grammar.md b/appendices/formal-grammar.md index 912947f..f6514f1 100644 --- a/appendices/formal-grammar.md +++ b/appendices/formal-grammar.md @@ -1,6 +1,12 @@ # 形式文法 -本附录集中列出正文采用的文法草案。文法说明可表达的源码结构;名称、类型、可见性与执行效果由相应章节定义。各主题的确定程度见[规范状态](specification-status.md)。 +本附录集中列出文法草案。文法说明可表达的源码结构;名称、类型、可见性与执行效果遵守相应语义约束。各主题的确定程度见[规范状态](specification-status.md)。 + +[对象类型与构造](../guide/07-top-level-types/README.md)采用候选的自身类型标注、trait、容器、任务及 Agent 实例记法。以下 EBNF 只覆盖列出的语法范围,不穷尽对象构造形式。 + +Object 是继承根,Object 和 Type 都是 Type 的实例,Type 继承 Object。实例化线与继承线属于类型语义;typeOf、basesOf 等反射接口与显式继承语法仍待定义。 + +class、agent 等构造入口自身是对象。以下产生式中的文字终结符描述候选构造记法,不据此将这些名称定为保留关键字;入口的类型、名称解析及调用语法尚待定义。 ## EBNF 记法 @@ -97,7 +103,7 @@ primary = identifier | string | number | symbol | "(", expression, ")" ; ``` -成员访问与调用先于一元负号,一元负号先于乘除,乘除先于加减。正文采用同级二元算术运算从左到右组合的规则。 +成员访问与调用先于一元负号,一元负号先于乘除,乘除先于加减。同级二元算术运算从左到右组合。 此处能表达成员调用,不代表某个类型自动拥有相应成员。数据读取提案使用同一套表达式文法,没有单独的 get 关键字。 diff --git a/appendices/framework-runtime-lifecycles.md b/appendices/framework-runtime-lifecycles.md new file mode 100644 index 0000000..ae6a0ca --- /dev/null +++ b/appendices/framework-runtime-lifecycles.md @@ -0,0 +1,468 @@ +# 框架如何接管代码执行 + +框架通过保存定义、关联入口、管理活动状态和调用用户函数来组织执行。语言、执行引擎、宿主和框架的职责分别说明,才能判断一段代码何时运行、在哪运行,以及哪个实体一直存续。基础结构见[12 门语言的执行模型与生命周期](language-runtime-lifecycles.md),词法用途见[关键词手册](language-keywords.md)。 + +资料核对日期:2026-10-13。本文以普通 hosted C 进程、CPython/FastAPI/ASGI、Java/Spring Boot/Spring MVC、Unity 6.0,以及 TypeScript/React/Node/Chromium 的指定路径为案例。持续更新的官方文档与实现源码用于说明相应机制,不代表所有历史版本。代码展示预期行为,未作为执行日志;框架的开发模式、配置和替代后端会改变部分时序。 + +## 先确定每一层回答什么 + +| 层 | 职责 | 典型证据 | +| --- | --- | --- | +| 语言 | 调用、作用域、暂停、异常、类型等的语义 | Python、Java、C#、ECMAScript 等规范 | +| 编译或构建工具 | 检查和转换源码,准备可执行逻辑 | TypeScript 类型擦除、JSX 转换、C# 编译 | +| 执行引擎或原生执行环境 | 推进当前代码并维护必要执行状态 | CPython、JVM、V8、Mono、原生机器码 | +| 宿主 | 应用入口、I/O、系统事件、线程或事件循环、呈现能力 | ASGI 服务器、Servlet 容器、Node、浏览器、Unity | +| 库或框架 | 入口映射、应用状态、组件或请求的组织 | FastAPI 路由、Spring bean、React 组件树 | + +这些是职责边界,不要求每层都是一个独立进程,也不保证每个产品只处在一层。Unity 同时提供引擎宿主与组件管理;Node 包含 V8、原生绑定及 libuv 等协作部分;浏览器还有渲染、网络及多进程组织,不能缩减成 V8 本身。 + +注册建立“条件与逻辑”的关系。外部事件或明确调用进入入口;调度机制安排执行机会;引擎执行本次函数。框架也会执行自己的代码,它调用用户函数时通常仍使用语言的普通调用机制。 + +## 路径一:C 普通进程 + +### 从启动到返回 + +这是一个完整的 hosted C 示例,不依赖应用框架。预期输出 `42` 并正常返回成功状态。 + +```c +#include + +static int price(int base) { + return base + 2; +} + +int main(void) { + int result = price(40); + printf("%d\n", result); + return 0; +} +``` + +```text +启动程序 + → 操作系统及实现的启动代码准备执行环境 + → 进入 main + → 用户调用 price,当前线程进入该函数 + → price 返回 42,继续 main + → printf 产生输出 + → main 正常返回,执行正常退出流程 +``` + +`price` 的函数定义不因“程序已经启动”而自己反复执行。这里没有应用任务队列:下一步由当前控制流确定;CPU 最终执行编译后的指令,OS 仍可调度执行线程。[C23 草案的 hosted 启动与终止](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf) + +### 谁持有状态 + +| 实体 | 保存的信息 | 结束方式 | +| --- | --- | --- | +| 程序及静态存储 | 可执行代码与长期数据 | 正常退出或进程终止 | +| `main` 调用 | `result`、当前进度及调用关系 | 返回 | +| `price` 调用 | `base` 及临时计算 | 返回 42;典型原生调用状态结束 | +| 输出设施 | 缓冲和 OS 资源 | 库及退出协议处理 | + +实际 ABI 可以用栈、寄存器和内联等实现调用。语言规定调用结果,具体执行布局由实现决定。添加 GUI 库或 HTTP 服务器后,入口还会增加库管理的事件关系;C 语言本身没有因此改变。 + +## 路径二:FastAPI + +### 注册路由与处理请求是两个动作 + +以下内容是可交给 ASGI 服务器加载的 Python 模块。`sleep` 用于展示可暂停等待,不代表真实数据库实现。预期请求 `GET /price?base=40` 得到 JSON 数据 `{"price":42}`。 + +```python +import asyncio +from fastapi import FastAPI + +app = FastAPI() + +@app.get("/price") +async def price(base: int = 40): + await asyncio.sleep(0.01) + return {"price": base + 2} +``` + +加载模块时执行导入、创建 `app`、创建函数及应用装饰器;装饰器把路径、方法和函数等关联起来。它不在注册时替未来每个请求执行 `price` 函数体。请求进入后,框架才使用这份关联选择处理函数。 + +服务器以 Uvicorn 为例;事件循环可使用 asyncio 或其兼容实现,而非只能使用 CPython 中某个唯一固定循环。[Uvicorn 事件循环选择](https://uvicorn.dev/concepts/event-loop/) + +### 一次请求经过哪些层 + +```mermaid +sequenceDiagram + participant Client as 客户端 + participant Server as ASGI 服务器与事件循环 + participant App as FastAPI 与 Starlette + participant Handler as 用户 price 协程 + Client->>Server: GET /price?base=40 + Server->>App: 调用应用:scope、receive、send + App->>App: 路由、参数与依赖处理 + App->>Handler: 调用并推进协程 + Handler->>Server: 可暂停等待 + Note over Handler: 局部状态和继续关系被保留 + Server->>Handler: 条件满足后安排继续 + Handler-->>App: 返回字典 + App->>Server: 生成并发送响应事件 + Server-->>Client: HTTP JSON 响应 +``` + +图示压缩了中间件和序列化细节。ASGI 的 HTTP `scope` 对应一次请求,WebSocket `scope` 则可贯穿整个连接;HTTP keep-alive 不把多个请求合并为同一次处理函数调用。服务器提供协议事件,应用通过可等待的 `receive`/`send` 接收与发送。[ASGI 规范](https://asgi.readthedocs.io/en/latest/specs/main.html) + +| 结构 | 保存的信息 | 管理者与存续 | +| --- | --- | --- | +| 模块及 `app`、路由定义 | 应用配置和入口映射 | 模块/框架,跨多个请求 | +| 请求 scope、Request、依赖求值状态 | 方法、路径、头、输入及本次依赖 | 服务器/Starlette/FastAPI,围绕请求 | +| coroutine 继续状态 | `base` 等局部状态、等待后的进度 | Python 执行机制,围绕本次处理 | +| Task 及事件循环的等待管理 | 活动状态、等待结果和恢复安排 | ASGI 服务器选定的异步环境 | +| 响应对象与输出事件 | 状态码、头及 body | 框架/服务器,直至相应发送流程结束 | + +### 同步函数和异步函数的执行位置 + +FastAPI 通过框架调用的普通 `def` 路由函数和同步依赖,通常交给外部线程池;`async def` 路由在异步调用链中推进。这个区别只适用于它负责调用的设施:用户自己在 async 路由中直接调用普通辅助函数,仍是普通同步调用,不自动被挪到线程池。异步函数中的 CPU 循环或阻塞 I/O 仍能阻碍事件循环。[FastAPI 的技术说明](https://fastapi.tiangolo.com/async/#very-technical-details) + +### 应用、请求和依赖分别清理 + +应用的 `lifespan` 上下文管理共享资源:进入部分用于应用接收请求前的准备,退出部分用于关闭。带 `yield` 的依赖围绕更小的工作范围获取和释放资源。当前文档区分 `scope="function"` 的函数退出清理与 `scope="request"` 的响应发送后清理;不要把两者写成一个固定时间点。[应用 lifespan](https://fastapi.tiangolo.com/advanced/events/)、[带 yield 依赖的 scope](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#early-exit-and-scope) + +处理函数返回不意味着应用退出;请求结束不意味着共享连接池必须销毁。失败进入异常处理路径,取消及断连的传播要结合服务器、中间件和被等待操作判断,不能承诺客户端断开后所有业务效果立即停止或回滚。 + +## 路径三:Spring Boot + +### 从入口启动容器 + +基线是使用 Spring MVC 的应用及嵌入式 Servlet 容器,Tomcat 可作为例子。Spring Boot 组织启动与配置;Spring 的 `ApplicationContext` 管理 bean;Servlet 容器接入 HTTP;JVM 执行 Java 方法。这些不是同一个生命周期。 + +下面是 `example.pricing` 包中的 `PriceApplication.java` 示例,前提是项目具有相应 Spring Boot Web 依赖。预期请求 `GET /price?base=40` 返回包含 `price: 42` 的 JSON 对象。 + +```java +package example.pricing; + +import java.util.Map; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +public class PriceApplication { + public static void main(String[] args) { + SpringApplication.run(PriceApplication.class, args); + } + + @RestController + static class PriceController { + @GetMapping("/price") + public Map price( + @RequestParam(name = "base", defaultValue = "40") int base) { + return Map.of("price", base + 2); + } + } +} +``` + +启动时由容器读取配置、发现并创建所需 bean、注入依赖及调用相应初始化设施。映射注解是供框架使用的元数据;Java 的 `@GetMapping` 拼写不是新增 Java 关键词,声明它也不等于马上处理请求。[Spring Boot 的启动](https://docs.spring.io/spring-boot/reference/features/spring-application.html)、[bean 与依赖注入](https://docs.spring.io/spring-boot/reference/using/spring-beans-and-dependency-injection.html) + +### 请求怎样进入 controller + +```text +HTTP 请求 + → Servlet 容器接入并安排处理 + → Filter 等链路 + → DispatcherServlet + → HandlerMapping 查找匹配的处理器 + → HandlerAdapter 配合参数解析等设施调用 controller 方法 + → JVM 推进本次 Java 调用 + → 返回值处理及消息转换形成 JSON 响应 + → 容器写回客户端 +``` + +这里选择 `@RestController` 的数据响应路径;返回视图名的 controller 还会涉及视图解析。URL 没有一个“执行 Java”的特殊开关,服务端配置的分派逻辑决定产生响应的方法。[DispatcherServlet](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet.html)、[请求处理序列](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet/sequence.html) + +| 结构 | 保存的信息 | 管理者与存续 | +| --- | --- | --- | +| JVM 的类、方法元数据 | 编译后的 Java 逻辑 | JVM/类加载器 | +| bean definition 与 ApplicationContext | 创建配方、依赖关系及受管理实例 | Spring,跨请求或按配置的 scope | +| 请求映射与 handler 元数据 | 路径、方法、参数及调用入口 | Spring MVC,跨请求 | +| Servlet 请求/响应及分派状态 | 本次 HTTP 数据和处理关联 | 容器及框架,围绕一次请求 | +| JVM 方法 frame | 参数、局部变量及方法进度 | 本次 Java 调用 | + +默认 singleton bean 在容器内被复用,不是每个请求都创建一个 controller。方法 frame 是本次调用的状态;把请求数据存入复用实例字段会涉及并发访问。这是实例存续与请求存续不同带来的后果。prototype 等 scope 的退出管理也有不同保证,不能认为所有 bean 都由容器完整管理至销毁。[Spring bean scope](https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html) + +### 初始化、请求返回与关闭 + +Spring 可以调用 `@PostConstruct`、初始化接口或配置的 init 方法;正常关闭时可调用 `@PreDestroy` 等销毁设施。`Lifecycle`/`SmartLifecycle` 还表达受管理活动的启停。回调由容器在相应条件下调用,不由 Java GC 替代;具体 bean scope 的管理保证需要分别核对。[Spring bean 生命周期](https://docs.spring.io/spring-framework/reference/core/beans/factory-nature.html) + +请求方法返回后应用继续存续。Boot 的正常退出支持关闭 ApplicationContext 的安排;强制终止不能被当作所有清理钩子都会执行的正常关闭。[Spring Boot 应用退出](https://docs.spring.io/spring-boot/reference/features/spring-application.html#features.spring-application.application-exit) + +### WebFlux 是另一种请求模型 + +Spring Boot 并不只代表 Servlet 阻塞模型。WebFlux 使用非阻塞契约、响应式组合及服务器适配;通常用较少的事件循环工作线程推进活动,和 MVC 常见的阻塞处理假设不同。`Mono`/`Flux` 保存或组合数据流协议,不等同于每个请求专属的一条 JVM 调用栈。这里的 Reactor `Mono` 是响应式库类型,与 Unity 的 Mono 执行后端无关。MVC 也能使用异步设施,不能把二者概括成“Java 一定阻塞”和“Java 一定事件循环”。[Spring WebFlux 的并发模型](https://docs.spring.io/spring-framework/reference/web/webflux/new-framework.html) + +## 路径四:Unity + +### 执行后端与阶段安排是两个问题 + +Unity 的 C# 脚本通常先编译为 IL 等内容。Mono 后端提供托管执行与 JIT;IL2CPP 将 IL 转为 C++ 再编译为原生代码。不能直接把 Unity 写成桌面 CoreCLR 应用。无论采用哪条后端路径,引擎依然承担场景与组件管理,以及 PlayerLoop 的阶段调用安排。[Unity 脚本后端](https://docs.unity3d.com/6000.0/Documentation/Manual/scripting-backends.html) + +```text +开发准备:C# 源码 → IL → Mono 执行路径/IL2CPP 原生编译路径 + +应用运行:Unity 启动与场景准备 + → 建立 GameObject 与组件实例及关系 + → 根据对象活动、组件启用与阶段规则调用事件函数 + → PlayerLoop 推进输入、物理、脚本更新及其他系统 + → 场景卸载、禁用或销毁触发相应处理 +``` + +PlayerLoop 是引擎的一组系统阶段,还能通过相关 API 定制;并不是每一帧把项目里所有 C# 函数都运行一次。[Unity 事件执行顺序](https://docs.unity3d.com/6000.0/Documentation/Manual/execution-order.html) + +### 哪些回调在什么条件下进入 + +| 入口 | 管理条件 | 不能推出的结论 | +| --- | --- | --- | +| `Awake` | 组件实例加载、对象激活等符合条件的初始化,一实例调用一次 | 不是所有不活动对象都在场景加载时立即执行,也不是 C# 普通构造器 | +| `OnEnable` | 对象活动且组件启用时 | 不是一生只调用一次,可因再次启用进入 | +| `Start` | 启用后首次更新前的一次初始化 | 不保证与 Awake 同帧;禁用时可能延后 | +| `FixedUpdate` | 固定时间步的物理更新安排 | 每个显示帧可能零次、一次或多次 | +| `Update` | 符合条件的脚本帧更新 | 不是全部数据对象的通用钩子 | +| `LateUpdate` | 在 Update 后的相应阶段 | 不代替任意线程的同步协议 | +| `OnDisable` | 组件或对象退出启用活动等相应情形 | 禁用和销毁不是同一状态 | +| `OnDestroy` | 满足条件的组件或对象销毁 | 有适用边界;强制退出不能保证执行 | + +条件详见 [Awake](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.Awake.html)、[OnEnable](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnEnable.html)、[Start](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.Start.html)、[FixedUpdate](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.FixedUpdate.html)、[Update](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.Update.html)、[LateUpdate](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.LateUpdate.html)、[OnDisable](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnDisable.html)、[OnDestroy](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnDestroy.html)。 + +以下是应保存为 `PriceLabel.cs` 并挂在活动 GameObject 上的组件例子。这里用日志观察执行,不代表 UI 的正式绘制实现。 + +```csharp +using UnityEngine; + +public class PriceLabel : MonoBehaviour +{ + private int price; + + private void Awake() { price = 42; } + private void OnEnable() { Debug.Log("enabled"); } + private void Start() { Debug.Log(price); } + private void Update() { /* 每次符合条件的更新处理 */ } + private void OnDisable() { Debug.Log("disabled"); } +} +``` + +在常规初始化条件下,实例准备→Awake→OnEnable→Start→后续 Update。重新禁用再启用,可以再发生 OnEnable;这不意味着 price 字段被重新创建或 Start 再次执行。同类不同对象的调用顺序不能仅凭源码文件排列推断。 + +### 哪些状态跨帧存在 + +| 结构 | 保存的信息 | 管理者与存续 | +| --- | --- | --- | +| 场景、GameObject 与组件关系 | 对象组织、活动及启用状态 | Unity 引擎,跨帧 | +| 脚本实例及字段 | `price` 等长期组件状态 | 托管对象及引擎对象关联,跨回调 | +| 每次 Update 等的方法调用状态 | 本次局部变量和当前进度 | 执行后端,一次回调 | +| IEnumerator 状态机与协程等待记录 | 跨 yield 的局部数据、继续位置及等待条件 | 编译器表示及 Unity 协程调度 | +| 引擎资源与托管引用 | 场景对象、资源及引用关系 | 引擎销毁和托管回收分别处理 | + +普通 `Update` 返回后,下帧是另一次函数调用;Unity 协程 `yield return` 后则由引擎按等待条件继续迭代状态。`StartCoroutine` 不自动创建后台线程;同步耗时计算仍可占用主线程。停止条件也取决于对象、组件及协程 API,不能把“组件 disabled”当成所有任务统一取消协议。[Unity 协程](https://docs.unity3d.com/6000.0/Documentation/Manual/Coroutines.html) + +## 路径五:React + +### 构建不是应用运行的中间调度层 + +```text +开发及构建: +TS/TSX 源码 + → 类型检查、类型处理、JSX 转换及模块处理 + → 供目标宿主执行的 JavaScript + +运行: +浏览器:启动 JS → React 组织组件计算 → DOM 提交 → 浏览器呈现 +服务器:Node 执行 JS → React 服务端渲染 → 输出 HTML 等响应 +``` + +转换可以分散在 TypeScript、其他转换器和打包工具中;JSX 也可以先被保留。构建工具运行在 Node,不证明组件随后一定在 Node 执行。React 是正在被执行的库代码,会组织用户组件及更新的调用;TS 类型通常已擦除。[TypeScript 的类型擦除](https://www.typescriptlang.org/docs/handbook/2/basic-types.html#erased-types)、[JSX 转换模式](https://www.typescriptlang.org/docs/handbook/jsx.html) + +### 浏览器首次显示与一次点击 + +下面是客户端入口 TSX 的例子,前提是页面中有 `id="root"` 的容器,且构建环境提供 React、React DOM 和相应类型声明。它是普通客户端渲染,不含 SSR。 + +```tsx +import { useEffect, useState } from "react"; +import { createRoot } from "react-dom/client"; + +function Price() { + const [price, setPrice] = useState(42); + + useEffect(() => { + const previousTitle = document.title; + document.title = `Price: ${price}`; + return () => { document.title = previousTitle; }; + }, [price]); + + return ; +} + +createRoot(document.getElementById("root")!).render(); +``` + +预期首次按钮显示 42,点击后显示 43;提交后的 Effect 同步相应标题。示例的非空断言不构成运行时容器创建,HTML 必须实际提供该节点。调用 root.render 提交渲染请求,也不能据此认为调用返回时所有 DOM 和 Effect 工作已经完成。[createRoot 与 render](https://react.dev/reference/react-dom/client/createRoot) + +| 步骤 | 谁进入或调用 | 保存或使用的状态 | +| --- | --- | --- | +| 加载入口 JS | 浏览器的脚本加载与求值机制 | JS 模块、函数及 React 库 | +| 首次 render 请求 | 入口调用 React root API | root、更新及组件关系 | +| 组件计算 | React 调用 `Price` | 本次调用的局部值,React 持有的 Hook 状态 | +| commit | React 调用 DOM 等宿主接口 | 已提交的树及 DOM 关系 | +| Effect setup | React 按 Effect 规则安排 | 依赖和返回的 cleanup | +| 用户点击 | 浏览器事件分派进入 React 事件处理,再调用用户处理逻辑 | 事件、组件关联及更新请求 | +| 后续更新 | React 处理状态更新,再组织 render/commit | 新状态,旧依赖及新依赖 | +| 卸载 | root 或组件树操作使组件退出 | Effect cleanup、宿主节点及关联清理 | + +render 是计算下一份界面描述,commit 才将相应变化应用到宿主。组件函数可以被多次调用;应保持渲染计算纯净,不能把“函数被调用一次”当作“一次业务操作已经提交”的保证。[React render 与 commit](https://react.dev/learn/render-and-commit)、[组件与 Hook 的纯度要求](https://react.dev/reference/rules/components-and-hooks-must-be-pure) + +### 状态为什么没有随组件函数返回而消失 + +React 持有组件关系及 Hook 状态,组件函数每次调用读取当前状态。普通局部变量随调用建立,`useState` 管理的状态则与 React 管理的组件身份关联,不能当作每次新建的普通局部值。[React 状态的保留与重置](https://react.dev/learn/preserving-and-resetting-state) + +| 结构 | 职责 | 所属层 | +| --- | --- | --- | +| JS 函数、闭包和本次调用状态 | 执行组件计算及事件函数 | JavaScript 引擎 | +| React element 等界面描述 | 表达本次计算所得结构 | React 库数据 | +| Fiber 与 root | 组件工作、父子关联、已保存状态、更新及待处理工作 | React 当前协调实现 | +| Hook 状态与 Effect 记录 | 状态、依赖及 cleanup 关联 | React 管理结构 | +| DOM 节点与事件设施 | 浏览器中的宿主呈现及交互 | 浏览器 | + +Fiber 是实现结构,源码包含子节点、相邻节点、更新队列和保存状态等信息。它不等于 V8 调用栈,也不是所有 React API 使用者必须直接创建的对象;字段和布局不是稳定应用 API。[React 实现中的 Fiber 类型](https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactInternalTypes.js) + +### React Hook 与 Unity 阶段回调的差别 + +`useState`、`useEffect` 等普通 Hook 必须服从顶层调用与顺序约束,它们不是可以任意在条件中增删的动态回调列表。`useEffect` 记录的 setup/cleanup 与依赖变化关联;`useState` 则管理状态,并不代表事件监听。特殊的 `use` API 有不同的调用规则,不能用“所有 use 开头函数都绝对相同”概括。[Hook 规则](https://react.dev/reference/rules/rules-of-hooks)、[use API](https://react.dev/reference/react/use) + +Effect 在组件提交后按相关规则同步外部系统;依赖变化时先清理旧关联,再建立新关联,卸载时清理。开发 Strict Mode 会增加用于检查的 setup/cleanup 周期。Effect 与浏览器实际绘制的先后不能简单固定为“每次 paint 之后”;`useEffect` 与 `useLayoutEffect` 的契约不同。[useEffect 的时序与边界](https://react.dev/reference/react/useEffect) + +Unity 主要用引擎命名阶段选择符合条件的组件回调;React 主要用更新、组件计算、提交和依赖关联组织 UI。React 不要求组件每个显示帧都重新计算,也没有为每个普通函数自动提供 Awake/Update。 + +### 可选的服务端渲染与 hydration + +```mermaid +sequenceDiagram + participant Browser as 浏览器进程 + participant Server as Node 服务器进程 + participant SSR as 服务器 React 渲染 + participant ClientReact as 浏览器 React + Browser->>Server: 页面请求 + Server->>SSR: 调用服务端渲染入口 + SSR-->>Server: HTML 流等结果 + Server-->>Browser: HTTP 响应与后续资源 + Browser->>Browser: 解析 HTML 并加载客户端 JS + Browser->>ClientReact: hydrateRoot 等入口 + ClientReact->>Browser: 关联交互逻辑与已有 DOM +``` + +`renderToPipeableStream` 是 Node 流环境的一条 React 服务端输出路径;浏览器的 `hydrateRoot` 接管已有的服务端 HTML 并建立客户端交互。初始渲染结果要符合 hydration 的一致性要求,不能把服务器函数对象、闭包或堆地址当成直接转移到浏览器的状态。[服务端流渲染](https://react.dev/reference/react-dom/server/renderToPipeableStream)、[hydrateRoot](https://react.dev/reference/react-dom/client/hydrateRoot) + +服务端和客户端分别拥有自己的 JS 执行环境与对象。Effects 不在服务端渲染时运行;需要客户端的交互逻辑仍由浏览器加载和执行。SSR、React Server Components、服务器函数与框架路由是不同机制;本节追踪传统 SSR/hydration,不把其他机制默认叠加进去。 + +## Node 与 Chromium + +### 请求得到什么与客户端怎么使用分别决定 + +服务端先按路由或静态资源配置生成响应,客户端再按请求用途、响应信息和自己的规则使用内容。URL 的后缀不能单独决定代码是在服务器执行还是在浏览器执行。 + +| 动作 | 服务端可能怎样生成响应 | 浏览器接收后的典型路径 | +| --- | --- | --- | +| 导航到页面 URL | 静态 HTML 或程序生成 HTML | 导航及文档解析、样式、布局和呈现 | +| 页面引用 `