当后端 Flowable 工作流处理完毕并得到结果时,如何将这个结果返回给前端 Bpmn.js,以及前端是根据 historyInstance
查询到执行完成再去发送请求,还是后端直接返回结果,这主要取决于你的业务需求和对实时性的要求。
这两种方式各有优缺点,下面我们来详细分析:
1. 前端通过 historyInstance
查询(轮询)
工作原理:
- 启动流程后,后端返回流程实例ID给前端。
- 前端定期向后端发送请求,查询 Flowable 的
historyInstance
API。 这个查询通常会带上之前获取到的流程实例ID。 - 后端调用 Flowable 的
historyService
查询流程或特定节点的历史状态。 - 当前端查询到流程或特定任务/节点的状态变为“完成”时, 它就知道可以发送一个新的请求给后端,去获取最终的业务处理结果。
优点:
- 实现简单直接: 对于不追求极致实时性的场景,这种方式开发起来相对简单。
- 解耦性好: 前后端相对独立,前端根据自己的节奏去拉取数据。
缺点:
- 实时性差: 结果的返回会有延迟,取决于你设置的
轮询间隔
。 - 增加服务器压力: 频繁的轮询会增加后端和 Flowable 的查询压力,尤其是在并发量高的情况下。
- 不必要的网络请求: 在流程未完成时,会产生很多无效的查询请求。
- 用户体验一般: 用户需要等待一段时间才能看到结果,可能感到卡顿或不流畅。
2. 后端直接通知前端
工作原理:
- Flowable 流程执行到关键节点(如:流程结束节点、特定服务任务完成节点),触发后端业务逻辑。 这通常通过在 Flowable 的服务任务 (Service Task) 中编写代码,或者使用 Flowable 事件监听器来实现。
- 后端获取到流程处理的最终结果。
- 后端直接将结果“推送”给前端。 这可以通过以下技术实现:
- WebSocket: 建立持久化的双向连接。后端可以直接向前端发送消息,实现实时通信。这是最推荐的方式。
- Server-Sent Events (SSE): 基于 HTTP 的单向通信,后端可以持续向前端推送事件流。适合后端只向前端发送更新的场景。
- 长轮询 (Long Polling): 前端发送请求后,后端不立即响应,而是等待有数据更新或超时后再响应。相比普通轮询
,减少了不必要的请求,但不如 WebSocket 实时
。
优点:
- 实时性强: 结果一旦产生,前端几乎可以立即接收到,用户体验极佳。
- 减少不必要的网络请求: 只有在有数据更新时才进行通信。
- 提升用户体验: 用户能即时看到流程进展和最终结果。
缺点:
- 实现复杂性增加: 需要引入 WebSocket 或 SSE 等技术,对后端和前端都有一定的开发成本。
- 服务器资源消耗: 维护大量的 WebSocket 连接可能会消耗一定的服务器资源。
推荐方案
综合来看,后端直接通知前端是更现代化、用户体验更好的方案,尤其推荐使用 WebSocket。
具体步骤建议:
- 在 Flowable 中设计流程: 当流程或某个关键任务完成时,添加一个服务任务 (Service Task)。
- 后端实现服务任务逻辑: 在这个服务任务中,编写 Java 代码(或你使用的后端语言代码),执行以下操作:
- 获取 Flowable 流程的最终结果或相关业务数据。
- 通过 WebSocket 连接,向前端发送一条消息。这条消息可以包含流程实例ID、当前状态、以及处理结果等信息。
- 前端 (Bpmn.js 应用) 建立 WebSocket 连接:
- 前端页面加载时,与后端建立 WebSocket 连接。
- 监听后端发送过来的 WebSocket 消息。
- 一旦收到后端发送的包含流程结果的消息,前端可以根据流程实例ID来更新 Bpmn.js 界面的状态,例如高亮已完成的节点,显示最终结果,或者触发其他业务逻辑。
WebSocket
:使用WebSocket实现前端和后端之间的实时双向通信,当后端状态发生变化时,立即通知前端更新状态。
轮询
:前端定期向后端发送请求,获取最新的运行状态。虽然这种方式不如WebSocket实时,但在某些场景下可能更简单。
轮询、SSE、WebSocket 选型对比与前端面试高频考点解析
一、核心对比与适用场景
以下是三种技术的核心差异与典型应用场景总结,建议结合业务需求选择:
维度 | 轮询(Polling) | SSE(Server-Sent Events) | WebSocket |
---|---|---|---|
通信方向 | 客户端→服务端(单向请求) | 服务端→客户端(单向推送) | 双向全双工通信 |
协议 | HTTP 短连接(每次请求独立) | HTTP 长连接(基于事件流) | TCP 自定义协议(需协议升级) |
实时性 | 依赖轮询间隔(秒级延迟) | 亚秒级(服务端主动推送) | 毫秒级(即时双向通信) |
开发复杂度 | 低(仅需 setInterval ) | 中(需处理连接状态) | 高(需管理握手、心跳、重连) |
浏览器兼容性 | 全兼容(包括 IE) | 现代浏览器(IE 不支持) | 现代浏览器(需降级方案) |
资源消耗 | 高(频繁建立 HTTP 连接) | 中(单长连接) | 高(维护 TCP 连接) |
适用场景 | 低频更新(如配置同步) | 服务端单向实时推送(如通知、监控) | 高频双向交互(如聊天、游戏) |
二、面试高频问题与解析
1. 如何选择技术方案?
考察点:对业务场景的理解与技术权衡能力。
参考回答:
- 优先选 SSE:若需服务端单向推送(如实时日志、消息通知),且无需复杂双向交互。
- 必选 WebSocket:若需双向高频通信(如在线协作、即时聊天)。
- 慎用轮询:仅作为兼容旧浏览器或极低频场景的降级方案。
示例:
“电商后台的订单状态更新适合用 SSE,因为服务端可主动推送变更;而实时对战游戏必须用 WebSocket 实现低延迟交互。”
2. SSE 如何实现自动重连?
考察点:对 SSE 特性的掌握。
参考回答:
SSE 内置自动重连机制(默认 3 秒),可通过 EventSource
的 reconnectionTime
属性调整间隔。若需自定义逻辑(如指数退避),可监听 error
事件:
const sse = new EventSource('/stream');
sse.onerror = (err) => {
console.log('连接失败,5秒后重试');
setTimeout(() => sse.close(), 5000);
};
3. WebSocket 如何兼容低版本浏览器?
考察点:兼容性解决方案。
参考回答:
- 降级方案:
- 长轮询(Long Polling):模拟实时性,但需手动管理请求队列。
- SSE + Polyfill:使用
eventsource-polyfill
兼容 IE。
- 替代协议:
使用Socket.IO
等库,自动处理协议降级(如长轮询→WebSocket)。
4. 轮询的优化技巧有哪些?
考察点:性能优化能力。
参考回答:
- 长轮询(Long Polling):服务端挂起请求直至数据更新,减少无效请求。
- 条件轮询:根据业务状态动态调整轮询频率(如无数据时延长间隔)。
- ETag 缓存:通过
If-None-Match
头避免重复传输相同数据。
5. 如何保证 WebSocket 消息的可靠性?
考察点:高并发与容错设计。
参考回答:
- 消息确认机制:客户端收到消息后返回 ACK,服务端重发未确认消息。
- 心跳检测:定时发送心跳包(如每 30 秒),超时则重连。
- 消息队列:服务端缓存离线消息,客户端重连后拉取。
三、实战场景与代码示例
场景 1:实时股票行情(SSE)
// 前端
const sse = new EventSource('/stock-prices');
sse.addEventListener('message', (e) => {
const data = JSON.parse(e.data);
updateChart(data); // 更新图表
});
// 后端(Node.js)
app.get('/stock-prices', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
const sendUpdate = () => {
res.write(`data: ${JSON.stringify(getStockData())}\n\n`);
};
setInterval(sendUpdate, 1000);
});
场景 2:聊天室(WebSocket)
// 前端
const ws = new WebSocket('wss://chat.com');
ws.onmessage = (e) => {
appendMessage(e.data);
};
ws.send(JSON.stringify({ text: 'Hello!' }));
// 后端(Node.js + ws 库)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (msg) => {
wss.clients.forEach(client => client.send(msg));
});
});
四、总结与进阶建议
-
选型原则:
- 单向推送 → SSE
- 双向交互 → WebSocket
- 兼容旧浏览器 → 长轮询 + SSE Polyfill
-
性能优化:
- 减少轮询频率,优先用 SSE/WebSocket
- WebSocket 消息压缩(如
permessage-deflate
)
-
面试加分项:
- 了解协议细节(如 SSE 的
id
和event
字段) - 掌握调试工具(如 Chrome 的 Network → WS 面板)
- 熟悉主流库(
Socket.IO
、RxJS
流处理)
- 了解协议细节(如 SSE 的
通过理解技术原理与业务场景的匹配关系,能在面试中清晰阐述选型逻辑,并展示解决复杂问题的能力。