免费 · 无需注册 · 支持 .mmd 文件

Mermaid 时序图编辑器

时序图按事情发生的先后展示参与方之间的消息,时间自上而下。当问题是谁按什么顺序调用了谁、又拿回了什么时用它——接口握手、认证流程、重试逻辑。如果重点是某一个组件内部的分支逻辑,流程图更合适。

OAuth 2.0 授权码流程

时序图的典型用武之地:四个参与方、一次用户看不见的跳转,以及一次必须在服务端之间完成的令牌交换。这种事用文字讲很吃力,用流程图则根本表达不出顺序。

sequenceDiagram
    autonumber
    participant U as 用户
    participant B as 浏览器
    participant A as 认证服务器
    participant API as 资源接口

    U->>B: 点击"登录"
    B->>A: GET /authorize?client_id&redirect_uri
    A-->>B: 跳转到登录页
    U->>A: 提交账号密码
    A-->>B: 302 跳回 redirect_uri 并带上 code
    B->>API: 用 code 请求 POST /token
    API->>A: 交换 code (服务端之间)
    A-->>API: access_token 与 refresh_token
    API-->>B: 下发会话 Cookie
    B-->>U: 登录完成
在编辑器中打开
广告

实例讲解

1. 两个参与方,一来一回

`->>` 是实线实心箭头,习惯上表示请求。`-->>` 是虚线,习惯上表示响应。这只是约定、并不强制,但破坏它会让图很难扫读。

sequenceDiagram
    客户端->>服务端: GET /orders
    服务端-->>客户端: 200 返回订单列表
在编辑器中打开

2. 别名与激活条

`participant X as 长名称` 能让箭头保持简短、方框保持可读。`activate` 和 `deactivate` 画出参与方处于忙碌状态的时间条——用来暴露一次很慢的下游调用非常合适。

sequenceDiagram
    participant API as 订单接口
    participant DB as Postgres

    API->>DB: SELECT * FROM orders
    activate DB
    DB-->>API: 返回 4200 行
    deactivate DB
    API->>API: 序列化响应
在编辑器中打开

3. 用 alt 和 opt 表达分支

`alt`/`else` 是二选一,`opt` 是可能不发生的步骤。这些块每一个都必须用 `end` 收尾——块没闭合是时序图最常见的错误,而且 Mermaid 会把它报在文件末尾而不是块本身。

sequenceDiagram
    participant C as 收银台
    participant P as 支付服务商

    C->>P: 授权 49.90 元
    alt 授权成功
        P-->>C: 返回授权码
        C->>C: 标记订单已支付
    else 授权失败
        P-->>C: 返回失败原因
        C->>C: 释放库存占用
    end
    opt 风控评分偏高
        C->>C: 转入人工复核队列
    end
在编辑器中打开

4. 重试循环与备注

`loop` 把重复的消息括起来,而 `Note over` 正适合写下读者否则一定会问的东西——超时时间、上限次数、为什么要限制重试。

sequenceDiagram
    participant W as 工作进程
    participant S as 搜索索引

    Note over W,S: 最多重试 5 次,之后进入死信队列
    loop 最多 5 次
        W->>S: PUT /documents/42
        S-->>W: 503 服务不可用
        W->>W: 指数退避等待
    end
    W->>W: 移入死信队列
在编辑器中打开

5. 并行处理与自调用

`par` 展示同时进行的工作——这恰恰是文字最难表达的。参与方指向自己的箭头,是在不虚构组件的前提下表现内部处理的正当写法。

sequenceDiagram
    participant O as 订单服务
    participant M as 邮件服务
    participant I as 发票服务
    participant A as 数据统计

    O->>O: 提交事务
    par 通知客户
        O->>M: 发送确认邮件
    and 生成单据
        O->>I: 生成发票 PDF
    and 记录指标
        O->>A: 上报 order_created 事件
    end
    O-->>O: 向调用方返回 201
在编辑器中打开

时序图语法速查

时序图有自己的一套箭头词汇。这些在流程图里都不成立,而流程图的箭头在这里多半也不是你以为的意思。

语法含义
sequenceDiagram开启该图。区分大小写——`sequencediagram` 会失败。
participant A声明参与方,同时固定从左到右的顺序。
participant A as 名称别名——箭头里用短 ID,方框里显示全名。
actor A与 participant 相同,但画成小人图标。
A->>B: 文字实线实心箭头。习惯上表示请求。
A-->>B: 文字虚线实心箭头。习惯上表示响应。
A->B: 文字实线,无箭头。
A-)B: 文字开口箭头——习惯上表示异步消息。
A-xB: 文字末端带叉的箭头——习惯上表示丢失或失败的消息。
activate A / deactivate A画出表示 A 正忙的激活条。
alt 条件 / else 条件 / end互斥分支。
opt 条件 / end可能不执行的块。
loop 文字 / end重复的消息。
par 文字 / and 文字 / end并发分支。
Note over A,B: 文字跨参与方的备注。也可用 `Note left of`、`Note right of`。
autonumber自动给每条消息编号。
广告

会让时序图报错的六个问题

均以 Mermaid 11.12.2 复现。把出错版本粘进编辑器即可看到确切报错,修正版本可正常渲染。

你会看到

报错指向图的最后一行

原因

有块被打开却从未闭合。`alt`、`opt`、`loop`、`par` 都需要配对的 `end`。Mermaid 直到输入耗尽才发现问题,于是把责任推给最后一行,而不是你漏掉的那个块。

解决办法

数一数开块的数量和 `end` 的数量。报错行如果是文件最后一行,几乎必然是这个原因。

错误写法
sequenceDiagram
    A->>B: 请求
    alt 成功
        B-->>A: 确认
正确写法
sequenceDiagram
    A->>B: 请求
    alt 成功
        B-->>A: 确认
    end

你会看到

在消息行上报 Parse error

原因

消息没有冒号。每个箭头后面都需要 `: 文字`,哪怕内容看上去不言自明。

解决办法

补上冒号和标签。

错误写法
sequenceDiagram
    客户端->>服务端 下单
正确写法
sequenceDiagram
    客户端->>服务端: 下单

你会看到

No diagram type detected matching given configuration

原因

关键字大小写写错了。Mermaid 的图类型关键字区分大小写,`sequencediagram` 与 `sequenceDiagram` 不是同一个标记。

解决办法

把 D 大写。

错误写法
sequencediagram
    A->>B: 你好
正确写法
sequenceDiagram
    A->>B: 你好

你会看到

Trying to inactivate an inactive participant (B)

原因

有 `deactivate` 却没有配对的 `activate`。与上面那些语法错误不同,这是一次语义检查,所以报错是一句可读的话而不是一堆标记——但图同样画不出来。

解决办法

让每个 `deactivate` 都有对应的 `activate`,或者干脆两个都去掉,让箭头自己说话。

错误写法
sequenceDiagram
    A->>B: 请求
    deactivate B
正确写法
sequenceDiagram
    A->>B: 请求
    activate B
    B-->>A: 响应
    deactivate B

你会看到

在参与方名称之后报 Parse error

原因

participant 声明里写了冒号。这条声明只接受一个名称或一个 `as` 别名,别的都不行。

解决办法

用 `as` 指定显示名称。

错误写法
sequenceDiagram
    participant API: 订单服务
    API->>DB: 查询
正确写法
sequenceDiagram
    participant API as 订单服务
    API->>DB: 查询

你会看到

`end` 变成了一个参与方,而不是结束块

原因

`end` 在这里同样是关键字。决定块在哪里结束的是标记而不是缩进,所以叫 `end` 的参与方会和块结束符撞车。

解决办法

永远不要把参与方命名为 `end`。改大小写或换个名字。

错误写法
sequenceDiagram
    A->>end: 收尾
正确写法
sequenceDiagram
    A->>Endpoint: 收尾

渲染须知

以下均为针对本站所用 Mermaid 11.12.2 的实测结果。时序图在两个方面与这里的其他图类型都不一样。

参与方名称用中文不会让图变宽

这是中文用户最容易担心、实际却不必担心的一点。实测把 `participant A as Order service` / `participant B as Payment provider` 换成 `订单服务` 和 `支付服务商`,渲染出的 viewBox 完全一致,都是 450×215。原因见下一条:时序图的宽度由参与方的数量和间距决定,而不是由标签长度决定——除非名称长到撑破默认间距,否则中文名称是免费的。

宽度取决于参与方数量,而不是消息数量

两个参与方之间的 3 条消息,viewBox 约为 450×309;同样两个参与方之间的 40 条消息是 450×2011——宽度纹丝不动。增加参与方会让图变宽,增加消息只会让它变长。实际结论是:超过大约六个参与方,时序图在笔记本屏幕上就宽到读不下去了,而这远在消息数量成为问题之前。

时序图的 viewBox 原点是负数

本站其他所有图类型的 viewBox 都从 `0 0` 开始,时序图从 `-50 -10` 开始——Mermaid 为参与方方框在左侧和上方预留了空间。如果你要对导出的 SVG 做后续处理,这一点很重要:默认原点为零的裁剪代码会把最左边的参与方切掉。

PNG 导出在这里是原生可用的

时序图的标签是普通 SVG 文本,而不是内嵌 HTML——这一点和流程图、类图、状态图、ER 图都不同。浏览器可以直接把它光栅化,所以时序图导出的 PNG 与屏幕上逐像素一致:不需要重新渲染,也不会有字体排版上的偏移。

每条消息大约占 45 像素高

用来在动笔之前估算一张图能不能塞进一页幻灯片。二十条消息大约 900 像素高,这差不多就是截图还能不滚动就看清的上限。

什么时候该换一种图

如果大部分消息都是某个参与方发给自己的,那你描述的是一个算法而不是一次对话,用流程图会更好读。

如果你开始在 `alt` 块里再套 `alt` 块,说明分支已经超出了这种图能承载的范围。时序图能把系统中的一条路径画得非常漂亮,把所有路径画得非常糟糕。在这里画正常路径,把异常处理放到另一张图里。

而如果你真正要传达的是系统里有哪些组件、它们如何连接——而不是它们按什么顺序通信——那么时序图帮不上忙。那是架构图,用 Mermaid 的流程图配合子图更合适。

其他图类型

作者 Dominik Malsch · 最后更新:

打开编辑器 →