Skip to content

Commit f3db234

Browse files
committed
chore: update docs
1 parent 28a7e4d commit f3db234

File tree

2 files changed

+69
-41
lines changed

2 files changed

+69
-41
lines changed

packages/guide/motion.cn.md

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,23 @@
22

33
## 前端业务模型
44

5-
在 Web 开发领域中,Web 服务的核心职责通常是接收请求、处理请求并返回响应,从系统建模的角度看,它是一个单输入单输出的处理过程。
6-
这使得 Web 服务的逻辑天然适合抽象为洋葱模型(onion model):外层中间件包裹内层中间件,请求按顺序穿透各层中间件进入核心业务处理逻辑,再逐层返回响应。常见的中间件包括身份验证、权限校验、日志记录、缓存处理等。
5+
在 Web 开发领域中,后端服务的核心职责通常是接收请求、处理请求并返回响应,从系统建模的角度看,它是一个典型的单输入单输出的处理流程。
6+
7+
这种特性使得后端服务的逻辑天然适合抽象为洋葱模型(Onion Model):外层中间件包裹内层中间件,请求按顺序穿透各层中间件进入核心业务处理逻辑,再逐层返回响应。常见的中间件包括身份验证、权限校验、日志记录、缓存处理等。
78

89
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
910
<img src="/model.drawio.svg" alt="motion" />
1011
</div>
1112

12-
而 Web 前端的业务模型与此完全不同。前端页面运行在用户浏览器中,是一个多输入多输出的复杂系统。它面向用户直接交互,输入来源包括用户点击、输入、滚动窗口变化、定时器触发、网络 API 响应等,这些事件发生的时间不确定、频率不一致,构成了一个**高度异步、事件驱动**的环境
13+
而 Web 前端的业务模型与此截然不同。前端应用运行在用户浏览器中,本质上是一个多输入多输出的复杂响应式系统。它直接面向用户交互,输入来源极其多样化:用户操作(点击、输入、滚动)、系统事件(窗口变化、定时器触发)、网络响应(API 调用、WebSocket 消息)等,这些事件在时间维度上不可预测、频率完全异构,构成了一个**高度异步、事件驱动**的执行环境
1314

14-
与此同时,前端系统也会产生多样化的输出,这些输出不再局限于一次性返回的响应,而是持续、分散地反馈到多个目标上。常见的输出包括更新页面中的 DOM 结构以反映状态变化,执行动画或过渡效果增强用户体验,发送新的 API 请求以拉取或提交数据,修改本地状态(如缓存、存储或组件状态)以准备后续交互甚至与浏览器原生功能交互(如剪贴板、通知、文件系统等),这些输出通常也是**动态分发、异步反馈**的方式
15+
与此同时,前端系统的输出同样复杂多样,不再局限于一次性的响应返回,而是持续、分散地作用于多个目标。典型的输出包括:DOM 更新(反映状态变化)、视觉反馈(动画、过渡效果)、网络通信(API 请求、数据提交)、状态同步(缓存更新、本地存储)、系统集成(剪贴板、通知、文件系统等浏览器 API),这些输出操作通常采用**动态分发、异步执行**的模式
1516

1617
复杂的输入和输出方式,与传统 Web 服务的“请求-响应”式单一输出形成鲜明对比。
1718

1819
## 前端框架的演化
1920

20-
为了应对前端页面中**高度异步、事件驱动、多输入多输出**的复杂环境,前端开发逐步演化出依托各种框架的编程范式,其中最具代表性的就是 `MVVM(Model-View-ViewModel)`框架
21+
为了应对前端应用中**高度异步、事件驱动、多输入多输出**的复杂环境,前端开发社区逐步演化出基于框架的编程范式,其中最具代表性的是 `MVVM(Model-View-ViewModel)` 架构模式
2122

2223
这一范式的核心思想是:将页面的显示逻辑与状态逻辑解耦,并通过**响应式绑定**让它们自动协同。
2324

@@ -40,13 +41,13 @@ MVVM 框架的最大优势在于:
4041

4142
## 复杂业务架构分层
4243

43-
虽然前端框架在处理数据变化更新页面这件事情上做的非常出色,但是随着业务的复杂度不断提升,框架提供出来的编程范式反而会将成为业务的瓶颈。前端框架的编程范式大多都是以组件为核心,以 hooks为颗粒度,将业务逻辑组织在组件中
44+
虽然现代前端框架在数据变化到视图更新的处理上已经非常成熟,但随着业务复杂度的指数级增长,框架原生的编程范式逐渐暴露出架构层面的局限性。主流前端框架普遍采用以组件为核心、以 Hooks/Composition API 为颗粒度的开发模式,将业务逻辑内聚在组件内部
4445

4546
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
4647
<img src="/page.drawio.svg" alt="motion" />
4748
</div>
4849

49-
将数据的请求、逻辑的处理统一放置在组件中进行处理,数据和逻辑链条通过组件树层层递进,功能也是通过组件来进行组织。对于简单业务这样做似乎没有问题,但是对于复杂业务,下面这些问题就会暴露出来
50+
在这种模式下,数据获取、业务逻辑处理都内聚在组件内部,业务功能通过组件树的层级关系进行组织,数据和逻辑链路沿着组件层次结构传递。这种架构对于中小型应用运行良好,但在企业级复杂业务场景下,会产生以下架构性问题
5051

5152
1. **组件过于臃肿**:数据的请求、数据的转换、数据的逻辑处理、全部堆在组件内部
5253
2. **代码阅读困难**:业务逻辑散落在各个组件中,需按照组件链条来理解业务
@@ -56,15 +57,15 @@ MVVM 框架的最大优势在于:
5657
6. **重复请求**:组件内部请求数据导致可以复用的数据难以复用
5758
7. **复杂度高**:数据流呈现螺旋网状调用,牵一发而动全身
5859

59-
如果认为前端状态是一系列数据和逻辑的总和,那么 Url 变化、DOM 元素的操作、定时器、http 请求等副作用导致状态在一直动态变化**界面其实是状态某一个时刻的切片**
60+
从架构设计角度来看,前端应用的状态是数据和逻辑的动态组合体,URL 路由、用户交互、定时任务、HTTP 请求等副作用操作持续驱动状态变迁。因此**UI 界面本质上是应用状态在特定时刻的快照**
6061

61-
将状态直接放入界面中其实是本末倒置,将状态从视图层抽离构造出业务模型,视图消费状态才符合上述理念
62+
将状态逻辑直接耦合在视图层是一种架构上的倒置,正确的做法应该是将状态管理从视图层解耦,构建独立的业务模型层,让视图成为状态的消费者
6263

6364
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
6465
<img src="/ddd.drawio.svg" alt="motion" />
6566
</div>
6667

67-
当将业务模型从组件抽离后,组件变成了**受控**只消费模型提供的数据。那么我们该如何组织业务模型呢?我们的代码已经不在组件内,`vue`或者`react`提供的编程范式也不再适用。
68+
业务模型从组件中抽离后,组件转变为**受控组件**专注于数据展示和用户交互,业务逻辑由独立的模型层负责。此时面临的核心问题是:在脱离了 Vue/React 组件体系后,如何有效地组织和管理这些业务模型?
6869

6970
## 模型驱动与流
7071

@@ -74,9 +75,9 @@ MVVM 框架的最大优势在于:
7475
<img src="/logic.drawio.svg" alt="motion" />
7576
</div>
7677

77-
从本质上来说,模型是高内聚的数据和逻辑的集合,似乎直接用`OOP`面相对象进行封装就可以达到目的,但是前面提到前端业务模型是**高度异步、事件驱动、多输入多输出**的,使用`OOP`进行封装,那么就会出现大量的异步调用链
78+
从理论上讲,业务模型是高内聚的数据和逻辑的封装体,传统的 OOP 面向对象编程似乎是自然的选择。然而,前端业务模型具有**高度异步、事件驱动、多输入多输出**的特性,使用传统 OOP 封装会产生大量复杂的异步调用链和回调嵌套
7879

79-
这些调用链条由于是**异步且往往横跨多个业务模型**导致代码难以阅读和维护,而`vue`的数据响应式往往会加剧这一问题,数据不知道在哪个环节被修改,修改后又可能不知情的触发其他逻辑,导致数据流变得难以追踪:
80+
这些调用链**异步执行且往往跨越多个业务域**极大增加了代码的理解和维护成本。Vue 的响应式系统虽然简化了数据绑定,但在复杂业务场景下可能加剧问题:数据修改的触发点难以定位,副作用的传播路径不可预测,整体数据流变得难以追踪和调试:
8081

8182
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
8283
<img src="/logic-complex.drawio.svg" alt="motion" />
@@ -88,19 +89,19 @@ MVVM 框架的最大优势在于:
8889
<img src="/logic-flow.drawio.svg" alt="motion" />
8990
</div>
9091

91-
流是一种对**异步编程声明式的高级抽象**通过流以及操作符,可以完成非常复杂的异步编排从而摆脱传统的复杂的调用逻辑关系
92+
流(Stream)是**异步编程的声明式高级抽象**通过流式操作符的组合,可以优雅地处理复杂的异步编排,从根本上解决传统回调和 Promise 链式调用的复杂性问题
9293

93-
当流的每个节点既可以存储数据,也可以处理数据,那么业务模型的 Data 和 Methods 也可以丢弃,全部以流的节点的形式来进行
94+
在流式架构中,每个节点既是数据容器也是处理单元,传统业务模型中的 Data 和 Methods 概念可以统一为流节点,实现数据和逻辑的一体化管理
9495

9596
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
9697
<img src="/logic-stream.drawio.svg" alt="motion" />
9798
</div>
9899

99-
这种以流为基础构成的前端业务模型,完美的契合了前端业务模型**高度异步、事件驱动、多输入多输出**的特点,它既可以很好的组织业务数据,也可以很好的组织业务业务逻辑
100+
基于流构建的前端业务模型完美契合了现代前端应用**高度异步、事件驱动、多输入多输出**的本质特征,在数据管理和业务逻辑组织方面都能提供更优雅、更可维护的解决方案
100101

101102
## 流在框架中落地
102103

103-
用流来组织业务模型,流的输入和输出都需要和前端框架进行交互,那么流如何转换为前端框架的可以消费的数据和逻辑呢?
104+
采用流式业务模型后,关键问题是如何实现流与前端框架的无缝集成。具体来说,需要解决双向转换问题:
104105

105106
- 对于`vue`来说,响应式的数据可以通过 [to$](/cn/useFluth/to$.html) 方法转换为流
106107

@@ -116,7 +117,7 @@ MVVM 框架的最大优势在于:
116117
<img src="/traditional-code.drawio.svg" alt="motion" />
117118
</div>
118119

119-
传统的开发方式一般采用的命令式的开发方式
120+
传统的前端开发采用命令式编程模式
120121

121122
1. 点击按钮后,调用 handleSubmit 方法
122123
2. handleSubmit 先 validateForm 方法,如果验证不通过,则提示报错
@@ -125,16 +126,16 @@ MVVM 框架的最大优势在于:
125126
5. 如果调用成功,则继续调用 handleDataB 方法、handleDataC 方法
126127
6. 如果调用失败,则提示报错
127128

128-
这种命令式的开发方夹杂着异步的操作,整体阅读体验非常差,随着业务逻辑的增加,handleSubmit 方法会变得越来越臃肿,难以维护
129+
这种命令式开发模式混合了同步逻辑和异步操作,代码可读性较差,随着业务复杂度增长,handleSubmit 方法会变得越来越臃肿,形成典型的"上帝方法"反模式
129130

130131
下面采用流的方式重新实现:
131132

132133
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
133134
<img src="/stream-code.drawio.svg" alt="motion" />
134135
</div>
135136

136-
而采用流的方式可以很好的解决这个问题,将基础数据拆分成一个个的流,通过流的组合操作符来完成业务,不管是代码阅读、维护都非常清晰,功能也趋于原子化,可以很好的复用
137+
流式编程则能优雅地解决这些问题:将基础数据抽象为独立的流,通过组合操作符构建业务逻辑,代码结构清晰、逻辑原子化、复用性强
137138

138-
注意其中的 [audit](https://fluthjs.github.io/fluth-doc/cn/api/operator/audit.html)[debounce](https://fluthjs.github.io/fluth-doc/cn/api/operator/debounce.html)[filter](https://fluthjs.github.io/fluth-doc/cn/api/operator/debounce.html)操作符,通过简单的操作符就完成了复杂的业务逻辑,让整体的代码阅读和维护都非常清晰
139+
值得注意的是,[audit](https://fluthjs.github.io/fluth-doc/cn/api/operator/audit.html)[debounce](https://fluthjs.github.io/fluth-doc/cn/api/operator/debounce.html)[filter](https://fluthjs.github.io/fluth-doc/cn/api/operator/debounce.html) 等操作符以声明式的方式处理了触发器、节流、条件过滤等复杂的异步控制逻辑,代码的表达力和可维护性都得到了显著提升
139140

140-
从这个例子中可以看出,采用流来组织业务代码,非常适合前端的业务模型
141+
通过这个对比案例可以看出,流式编程范式与前端业务的异步、事件驱动特性天然契合,是组织复杂前端业务逻辑的理想选择

0 commit comments

Comments
 (0)