变量引擎概念较多且抽象。本文通过 🌟 标记出了一批可以优先理解的概念。
变量引擎核心概念可以通过下图总结:
详见 变量介绍
在流程设计中,变量只关注定义,不关注值。变量的值在流程的运行时才会被动态计算。
作用域(Scope)是一种容器:容器内聚合了一系列变量信息,同时维护了与其他作用域的依赖关系。
作用域的范围可以根据业务场景的不同约定:
| 场景 | 示例 |
|---|---|
| 流程里节点可以约定为作用域 | ![]() |
| 全局变量侧边栏也可以约定为作用域 | ![]() |
| 界面编辑里组件(含变量)可以约定为作用域 | ![]() |
作用域(Scope)通过 AST 存储变量信息。
通过 scope.ast 可以访问作用域内的 AST 树,从而可以对变量信息进行 CRUD 操作。
ASTNode 是变量引擎 中用于存储变量信息的基本信息单元。它可以为各种变量信息建模。这些变量信息包括:
VariableDeclaration ,用于声明新变量。StringType,用于表示 String 类型。KeyPathExpression,用于对变量的引用。ASTNode 可以嵌套形成树(AST),表示复杂的变量结构。ASTNode 可以与 JSON 格式(ASTNodeJSON)相互转换,以便存储或传输。ASTNode 基类来添加新功能。ASTNode 值的变化会触发事件,从而实现响应式编程模式。ASTNodeJSON 是 ASTNode 的纯 JSON 序列化表示。
ASTNodeJSON 包含一个 kind 字段,用于表示 ASTNode 的类型:
用户在使用变量引擎时,通过 ASTNodeJSON 描述变量信息,然后通过变量引擎实例化为 ASTNode,并将其添加到作用域中。
ASTNodeJSON 和 ASTNode 的关系,类似于 React 中 JSX 和 VDOM 的关系
ASTNodeJSON 通过变量引擎实例化为 ASTNodeJSX 通过 React 引擎实例化为 VDOMJson Schema 是一种用于描述 JSON 数据结构的格式:
Json Schema 只描述了变量的类型信息,而 ASTNodeJSON 还可以包含变量的其他信息(如:变量的初始值)。ASTNodeJSON 可以通过变量引擎实例化为 ASTNode,从而实现响应式监听等能力。Json Schema 擅长描述 Json 的类型,而 ASTNodeJSON 可以通过自定义扩展定义行为更复杂的信息。在技术选型上,变量引擎内核需要更强大的扩展与表达能力,因此需要用 ASTNodeJSON 来描述更丰富更复杂的变量信息,如:通过定义变量的初始值,实现变量类型的动态推导 + 自动联动。
不过 Json Schema 作为业界通用的 JSON 类型描述格式,在易用性、跨团队沟通以及生态(如 ajv、zod)上更有优势。因此我 们在物料库中大量使用了 Json Schema,来降低大家的上手成本。
变量引擎提供了 ASTFactory,可以类型安全地创建 ASTNodeJSON:
声明 = 标识符(Key) + 定义(Definition)。在设计态中,声明是一种存储标识符 + 变量信息的 ASTNode。
变量声明 = 标识符 + 变量定义(类型 + 初始值)
函数声明 = 标识符 + 函数定义(函数入参出参 + 函数体实现)
结构体声明 = 标识符 + 结构体定义(字段 + 类型)
标识符是声明的索引,用于访问声明中的定义。标识符找到变量的类型定义,从而可以进行类型检查。变量引擎目前只提供了变量字段声明(BaseVariableField),并基于此扩展了变量声明(VariableDeclaration)和属性声明(Property)两种声明。
BaseVariableField)= 标识符 + 变量字段定义(类型 + 元信息 + 初始值)VariableDeclaration)= 全局唯一标识符 + 变量定义(类型 + 元信息 + 初始值 + 作用域内排序)Property)= Object 内唯一标识符 + 属性定义(类型 + 元信息 + 初始值)类型用于约束变量值的范围。在设计态中,类型是一种 ASTNode。
变量引擎内置了 JSON 的基础类型:
StringType:字符串IntegerType:整数NumberType:浮点数BooleanType:布尔值ObjectType:对象,可下钻 Property 声明。ArrayType:数组,可下钻其他类型。同时新增了:
MapType:键值对,键和值都可以进行类型定义。CustomType:由用户进行自定义扩展,如日期、时间、文件类型等。表达式输入 0 个或者多个变量,并通过通过特定方式进行计算,返回一个新的变量。
而在设计态中,表达式是一种 ASTNode,建模中我们只需关注:
假设我们有一个用 JavaScript 代码描述的表达式 ref_var + 1
表达式使用了哪些变量声明 ?
ref_var 标识符对应的变量声明表达式的返回类型是怎么推导的 ?
ref_var 的类型为 IntegerType,则 ref_var + 1 的返回类型为 IntegerTyperef_var 的类型为 NumberType,则 ref_var + 1 的返回类型为 NumberTyperef_var 的类型为 StringType,则 ref_var + 1 的返回类型为 StringType
图中展示了一个常见的例子:批处理节点引用前序节点的输出变量,对其进行遍历处理,得到一个 item 变量。其中 item 的变量类型会随着前序节点输出变量的类型而自动变化。
这个例子的 ASTNodeJSON 可表示为:
变量的推导链路如下:
作用域链(Scope Chain)定义了一个作用域可以引用哪些作用域的变量。它是一个抽象类,具体的业务场景可以实现自定义的作用域链。
变量引擎内置了自由布局作用域链和固定布局作用域链两种作用域链实现。
依赖作用域 = 作用域可以访问哪些作用域的输出变量
可以通过 scope.depScopes 访问作用域的依赖作用域。
覆盖作用域 = 作用域的输出变量可以被哪些作用域访问