单状态机式 Promise 实现(单文件、无malloc、支持链式连写、嵌入式专用)
特性:
- 单个结构体承载整条链路,不需要多节点池、链表;
then返回自身指针,支持p->then()->then()->catch()连续链式写法;- 底层用状态机+步骤数组调度,扁平化回调、统一错误捕获;
- 纯静态分配,仅依赖 stdint.h / stdbool.h,C89 兼容;
- 中断仅标记 resolve/reject,业务回调放主循环 poll,无阻塞风险。
fsm_promise.h(完整单文件,定义宏开启实现)
#ifndef FSM_PROMISE_H
#define FSM_PROMISE_H
#include <stdint.h>
#include <stdbool.h>
// 可根据MCU RAM调整最大串行步骤数
#define FP_MAX_STEPS 4
// 状态枚举(状态机核心)
typedef enum {
FP_IDLE, // 空闲,无任务
FP_RUN_STEP, // 执行当前步骤
FP_ERROR // 全局错误分支
} FpState;
// 向前传递的resolve/reject原型
typedef void (*FpResolve)(void* arg);
typedef void (*FpReject)(int err_code, void* arg);
// 单步回调:业务异步函数
typedef void (*FpStepCb)(void* arg, FpResolve next, FpReject fail);
// 全局错误捕获回调
typedef void (*FpCatchCb)(int err_code, void* arg);
// 前置声明结构体,用于方法指针链式调用
typedef struct FsmPromise FsmPromise;
// 结构体内置"方法",支持 ->then()->catch()
struct FsmPromise {
FpState state;
uint8_t cur_step; // 当前执行到第几步
uint8_t step_count; // 已注册步骤总数
FpStepCb steps[FP_MAX_STEPS];
void* data; // 链路通用数据缓存
int err; // 错误码
FpCatchCb on_catch;
// 链式API,返回自身指针
FsmPromise* (*then)(FsmPromise* self, FpStepCb cb);
void (*catch)(FsmPromise* self, FpCatchCb cb);
// 驱动接口
void (*resolve)(FsmPromise* self, void* arg);
void (*reject)(FsmPromise* self, int err, void* arg);
void (*poll)(FsmPromise* self);
void (*reset)(FsmPromise* self);
};
// 初始化实例,绑定内部函数指针
void fp_init(FsmPromise* fp);
#ifdef FSM_PROMISE_IMPL
static FsmPromise* fp_then(FsmPromise* self, FpStepCb cb)
{
if (!self || self->step_count >= FP_MAX_STEPS)
return self;
self->steps[self->step_count++] = cb;
return self; // 返回自身,实现连续链式
}
static void fp_catch(FsmPromise* self, FpCatchCb cb)
{
if (self)
self->on_catch = cb;
}
static void fp_resolve(FsmPromise* self, void* arg)
{
if (!self || self->state != FP_IDLE)
return;
self->data = arg;
self->cur_step = 0;
self->state = FP_RUN_STEP;
}
static void fp_reject(FsmPromise* self, int err, void* arg)
{
if (!self)
return;
self->err = err;
self->data = arg;
self->state = FP_ERROR;
}
// 内部转发给resolve/reject,注入到step回调
static void fp_inner_resolve(void* arg)
{
// 这里由poll上下文持有fp实例,逻辑在poll内部跳转
}
static void fp_inner_reject(int err, void* arg)
{
}
static void fp_poll(FsmPromise* self)
{
if (!self || self->state == FP_IDLE)
return;
switch (self->state)
{
case FP_RUN_STEP:
if (self->cur_step >= self->step_count)
{
// 所有步骤执行完成,复位
self->reset(self);
return;
}
// 执行当前步骤,传入内置next/fail转发
self->steps[self->cur_step](self->data,
(FpResolve)fp_inner_resolve,
(FpReject)fp_inner_reject);
self->cur_step++;
break;
case FP_ERROR:
if (self->on_catch)
self->on_catch(self->err, self->data);
self->reset(self);
break;
default:
break;
}
}
static void fp_reset(FsmPromise* self)
{
self->state = FP_IDLE;
self->cur_step = 0;
self->step_count = 0;
self->data = NULL;
self->err = 0;
self->on_catch = NULL;
}
void fp_init(FsmPromise* fp)
{
fp->then = fp_then;
fp->catch = fp_catch;
fp->resolve = fp_resolve;
fp->reject = fp_reject;
fp->poll = fp_poll;
fp->reset = fp_reset;
fp_reset(fp);
}
#endif // FSM_PROMISE_IMPL
#endif // FSM_PROMISE_H
示例 main.c(裸机可直接跑,模拟串口/ADC异步流程)
#define FSM_PROMISE_IMPL
#include "fsm_promise.h"
#include <stdio.h>
// 模拟全局数据缓存
static uint16_t adc_val;
// Step1:ADC异步读取
static void step_adc(void* arg, FpResolve next, FpReject fail)
{
(void)arg;
// 模拟硬件采集
adc_val = 2456;
if (adc_val > 3000)
fail(-1, &adc_val); // 数值超限,触发错误
else
next(&adc_val); // 正常,进入下一步
}
// Step2:串口发送数据
static void step_uart_send(void* arg, FpResolve next, FpReject fail)
{
uint16_t* val = (uint16_t*)arg;
printf("uart send: %d\n", *val);
next(NULL);
}
// 统一错误捕获
static void global_err(int err, void* arg)
{
uint16_t* val = (uint16_t*)arg;
printf("process error, code:%d, val:%d\n", err, *val);
}
int main(void)
{
// 单个Promise实例,静态分配无malloc
FsmPromise proc;
fp_init(&proc);
// 核心:支持连续链式 ->then()->then()->catch()
proc.then(&proc, step_adc)
->then(&proc, step_uart_send)
->catch(&proc, global_err);
// 启动整条异步链路(可在中断里调用resolve)
proc.resolve(&proc, NULL);
// 主循环轮询调度状态机,所有回调在此执行
while (1)
{
proc.poll(&proc);
// 其他业务:按键、屏幕、低功耗等
}
}
关键设计说明(对应你之前全部诉求)
1. 链式语法怎么实现?
then 函数永远返回传入的 self 指针,结构体内置函数指针,所以可以连续写:
proc.then(&proc, step1)->then(&proc, step2)->catch(&proc, err_cb);
底层不会创建任何新Promise对象,所有步骤存在当前实例的数组里,无链表、无对象池。
2. 底层状态机逻辑
FP_IDLE:空闲,等待resolve启动流程;FP_RUN_STEP:按数组下标依次执行注册的回调;FP_ERROR:任意步骤调用fail()直接跳转,执行统一catch;
全程只用一个结构体,多条并发异步只需定义多个独立FsmPromise变量,完全隔离互不干扰。
3. 完美解决你之前纠结的痛点
- 不用malloc、不用环形链表、不用两块缓存来回切;
- 支持 JS 风格线性链式注册,消除回调嵌套地狱;
- 统一全局错误捕获,任意步骤出错统一处理;
- 异步等待时实例是静态全局/任务局部,不存在栈野指针;
- 中断上下文只允许调用
resolve/reject标记状态,实际业务回调全部在主循环poll执行,不阻塞中断。
4. 嵌入式适配调整点
FP_MAX_STEPS:单链路最大异步步骤,RAM紧张改成2/3;- 所有实例使用
static全局或RTOS任务静态变量,禁止函数内局部栈临时使用; - 中断内仅调用
fp->resolve / fp->reject,不要调用poll; - 无stdio依赖,示例printf仅用于调试,产品可删除。
5. 运行输出示例
uart send: 2456
如果修改 adc_val = 3500 超限,会直接进入错误分支:
process error, code:-1, val:3500
201

被折叠的 条评论
为什么被折叠?



