文章目录
-
- 一、Promise核心设计目标
- 二、核心实现原理
- 三、完整源代码实现
- 四、核心模块逐行解析
-
- [1. 空类型`undefined`:解决"无错误信息"场景](#1. 空类型
undefined:解决“无错误信息”场景) - [2. 模板参数设计:强类型适配任意场景](#2. 模板参数设计:强类型适配任意场景)
- [3. 状态机实现:确保状态转换安全](#3. 状态机实现:确保状态转换安全)
- [4. 构造函数:注入异步逻辑](#4. 构造函数:注入异步逻辑)
- [5. 链式调用`then`:支持结果转换与错误透传](#5. 链式调用
then:支持结果转换与错误透传) - [6. 终结`then`:处理最终结果](#6. 终结
then:处理最终结果)
- [1. 空类型`undefined`:解决"无错误信息"场景](#1. 空类型
- 五、使用示例:覆盖常见异步场景
- 六、编译与运行
- 七、核心优势与扩展方向
- 八、总结
在C++开发中,异步编程(如模拟网络请求、文件读写)常面临"回调地狱""状态管理混乱""异常难以捕获"等问题。前端Promise的出现完美解决了这些痛点,但C++缺乏原生支持。本文将带大家从零实现一个 通用C++ Promise组件 ------纯标准库依赖,支持强类型结果/错误传递、链式调用、异常安全,可直接集成到任何C++项目中。
一、Promise核心设计目标
一个实用的Promise组件需满足以下核心需求:
- 状态管理:支持3种互斥状态(Pending/已完成Fulfilled/已拒绝Rejected),状态一旦转换不可逆;
- 回调机制:支持注册成功(onFulfilled)/失败(onRejected)回调,状态变更时自动触发;
- 链式调用:支持多步异步操作串联,结果可无缝转换,错误自动透传;
- 强类型支持 :适配任意结果类型(如
std::vector<int>、自定义结构体)和错误类型(如错误码、空类型); - 异常安全:捕获异步操作中的异常,自动转为失败状态,避免程序崩溃;
- 无依赖:仅使用C++标准库,不引入第三方框架。
二、核心实现原理
Promise的本质是"状态机+回调链":
- 状态机:通过枚举管控3种状态,确保状态转换的唯一性和不可逆性;
- 回调链:通过
then方法注册回调,链式调用时生成新Promise,实现结果透传与转换; - 类型适配:通过模板参数
ResultT(成功结果类型)和ErrorT(失败错误类型)支持任意类型。
三、完整源代码实现
cpp
#ifndef PROMISE_H
#define PROMISE_H
#include <functional>
#include <utility>
#include <stdexcept>
// 空类型标识:用于"失败时无需传递额外错误信息"的场景
struct undefined {};
template <typename ResultT, typename ErrorT = undefined>
class Promise {
public:
// 回调函数类型定义(强类型约束)
using ResolveCallback = std::function<void(ResultT)>; // 成功回调:接收ResultT类型结果
using RejectCallback = std::function<void(ErrorT)>; // 失败回调:接收ErrorT类型错误
using Executor = std::function<void(ResolveCallback, RejectCallback)>; // 执行器:封装异步逻辑
// 构造函数:接收执行器(异步任务),初始化状态为Pending
explicit Promise(Executor executor) : m_state(State::Pending) {
// 封装框架内部的resolve逻辑:状态转换+结果存储+触发回调
ResolveCallback resolve = [this](ResultT result) {
if (m_state != State::Pending) return; // 状态已变更,忽略重复调用
m_result = std::move(result); // 移动语义:避免拷贝,提升性能
m_state = State::Fulfilled; // 状态转为"已完成"
triggerCallbacks(); // 触发成功回调
};
// 封装框架内部的reject逻辑:状态转换+错误存储+触发回调
RejectCallback reject = [this](ErrorT error) {
if (m_state != State::Pending) return; // 状态已变更,忽略重复调用
m_error = std::move(error); // 移动语义存储错误信息
m_state = State::Rejected; // 状态转为"已拒绝"
triggerCallbacks(); // 触发失败回调
};
// 执行用户传入的异步逻辑,捕获所有异常并转为reject
try {
executor(std::move(resolve), std::move(reject));
} catch (...) {
reject(ErrorT()); // 异常时自动触发失败回调
}
}
// 链式调用接口:接收成功回调,返回新Promise(支持结果类型转换)
template <typename NewResultT>
Promise<NewResultT, ErrorT> then(std::function<NewResultT(const ResultT&)> onFulfilled) {
// 返回新Promise,将当前Promise的结果传递给新Promise
return Promise<NewResultT, ErrorT>([this, onFulfilled](
ResolveCallback newResolve, RejectCallback newReject
) {
// 注册当前Promise的成功回调:转换结果并触发新Promise的resolve
m_onFulfilled = [onFulfilled, newResolve, newReject](const ResultT& result) {
try {
NewResultT newResult = onFulfilled(result); // 结果类型转换(如T→U)
newResolve(std::move(newResult)); // 触发新Promise的成功状态
} catch (...) {
newReject(ErrorT()); // 转换失败时触发新Promise的失败状态
}
};
// 注册当前Promise的失败回调:错误透传(无需额外处理,直接传递给新Promise)
m_onRejected = [newReject](const ErrorT& error) {
newReject(error);
};
triggerCallbacks(); // 若当前Promise已完成,立即触发回调
});
}
// 终结回调接口:接收成功+失败回调,无返回值(用于链式调用的最后一步)
void then(
std::function<void(const ResultT&)> onFulfilled,
RejectCallback onRejected = {} // 失败回调可选,默认空
) {
m_onFulfilled = std::move(onFulfilled);
m_onRejected = std::move(onRejected);
triggerCallbacks(); // 若状态已完成,立即触发回调
}
private:
// Promise状态枚举(严格互斥)
enum class State {
Pending, // 初始状态:异步操作未完成
Fulfilled, // 成功状态:异步操作完成,有结果
Rejected // 失败状态:异步操作出错,有错误信息
} m_state;
ResultT m_result; // 成功时存储的结果(仅Fulfilled状态有效)
ErrorT m_error; // 失败时存储的错误(仅Rejected状态有效)
std::function<void(const ResultT&)> m_onFulfilled; // 外部注册的成功回调
std::function<void(const ErrorT&)> m_onRejected; // 外部注册的失败回调
// 触发回调:根据当前状态调用对应的回调函数
void triggerCallbacks() {
if (m_state == State::Fulfilled && m_onFulfilled) {
m_onFulfilled(m_result); // 成功状态:调用成功回调
} else if (m_state == State::Rejected && m_onRejected) {
m_onRejected(m_error); // 失败状态:调用失败回调
}
}
};
#endif // PROMISE_H
四、核心模块逐行解析
1. 空类型undefined:解决"无错误信息"场景
cpp
struct undefined {};
- 作用:当异步操作失败时无需传递额外错误信息(如"URL不存在""文件未找到"),用
undefined作为ErrorT模板参数,替代C++中void作为模板参数的尴尬; - 优势:保持模板类型统一性,避免单独处理
void类型,简化代码逻辑。
2. 模板参数设计:强类型适配任意场景
cpp
template <typename ResultT, typename ErrorT = undefined>
class Promise { ... };
ResultT:成功时的结果类型(如int、std::string、std::vector<Product>);ErrorT:失败时的错误类型(默认undefined,可自定义为int错误码、std::string错误信息);- 强类型约束:回调函数参数类型与模板参数强制匹配,编译器自动校验,避免类型错误。
3. 状态机实现:确保状态转换安全
cpp
enum class State { Pending, Fulfilled, Rejected } m_state;
- 状态特性:初始为
Pending,仅能转换为Fulfilled或Rejected,一旦转换不可逆; - 安全防护:
resolve和reject回调中先判断m_state == Pending,避免重复触发(如多次调用resolve无效)。
4. 构造函数:注入异步逻辑
cpp
explicit Promise(Executor executor) : m_state(State::Pending) { ... }
- 核心逻辑:接收用户传入的异步任务(
Executor),封装框架内部的resolve和reject,并传递给用户; - 异常捕获:用
try-catch捕获异步任务中的所有异常,自动转为reject状态,避免程序崩溃; - 移动语义:
std::move(resolve)/std::move(reject)减少拷贝成本,尤其适合大数据场景(如std::vector)。
5. 链式调用then:支持结果转换与错误透传
cpp
template <typename NewResultT>
Promise<NewResultT, ErrorT> then(...) { ... }
- 结果转换:上一个Promise的
ResultT可通过回调函数转换为新的NewResultT(如std::vector<Product>→int(商品总数)); - 错误透传:上一个Promise的错误自动传递到下一个Promise,无需重复编写错误处理逻辑;
- 即时触发:若上一个Promise已完成(如同步返回结果),新
then注册后立即触发回调,兼容同步/异步场景。
6. 终结then:处理最终结果
cpp
void then(std::function<void(const ResultT&)> onFulfilled, RejectCallback onRejected = {}) { ... }
- 用途:链式调用的最后一步,无需返回新Promise(如打印结果、提示错误);
- 灵活配置:失败回调可选,若仅需处理成功场景,可只传递成功回调。
五、使用示例:覆盖常见异步场景
示例1:基础异步操作(无错误信息)
模拟网络请求,成功返回字符串,失败无错误信息:
cpp
#include "Promise.h"
#include <iostream>
#include <chrono>
#include <thread>
// 模拟网络请求:2秒后返回成功结果
Promise<std::string, undefined> mockNetworkRequest(const std::string& url) {
return Promise<std::string, undefined>([url](auto resolve, auto reject) {
std::thread([url, resolve, reject]() {
// 模拟网络延迟2秒
std::this_thread::sleep_for(std::chrono::seconds(2));
if (url == "https://api.success.com") {
resolve("请求成功!返回数据:{name: 'MiniDataX'}");
} else {
reject(undefined()); // 失败无错误信息
}
}).detach();
});
}
int main() {
std::cout << "发起请求..." << std::endl;
mockNetworkRequest("https://api.success.com")
.then(
// 成功回调
[](const std::string& data) {
std::cout << "成功:" << data << std::endl;
},
// 失败回调
[](undefined) {
std::cout << "失败:请求地址不存在" << std::endl;
}
);
// 等待异步操作完成(避免主线程退出)
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}
示例2:链式调用(结果类型转换)
模拟"请求数据→解析数据→计算结果"的多步异步流程:
cpp
#include "Promise.h"
#include <iostream>
#include <vector>
// 步骤1:模拟请求商品列表(ResultT=std::vector<float>,商品价格列表)
Promise<std::vector<float>, int> fetchProductPrices() {
return Promise<std::vector<float>, int>([](auto resolve, auto reject) {
// 模拟异步请求
std::vector<float> prices = {99.9f, 199.9f, 299.9f};
if (!prices.empty()) {
resolve(prices); // 成功返回价格列表
} else {
reject(404); // 失败返回错误码404
}
});
}
int main() {
fetchProductPrices()
// 步骤2:转换结果:计算总价(std::vector<float> → float)
.then([](const std::vector<float>& prices) {
float total = 0.0f;
for (float p : prices) total += p;
return total;
})
// 步骤3:最终处理:打印总价(float → 无返回值)
.then([](float total) {
std::cout << "商品总价:" << total << "元" << std::endl;
}, [](int errCode) {
std::cout << "请求失败,错误码:" << errCode << std::endl;
});
return 0;
}
示例3:自定义错误类型(字符串错误信息)
失败时返回字符串错误信息,更直观:
cpp
// 模拟文件读取:成功返回文件内容,失败返回错误信息(ErrorT=std::string)
Promise<std::string, std::string> readFile(const std::string& filename) {
return Promise<std::string, std::string>([filename](auto resolve, auto reject) {
if (filename == "config.txt") {
resolve("数据库地址:localhost:3306"); // 成功返回文件内容
} else {
reject("文件不存在:" + filename); // 失败返回字符串错误
}
});
}
int main() {
readFile("config.txt")
.then(
[](const std::string& content) {
std::cout << "文件内容:" << content << std::endl;
},
[](const std::string& errMsg) {
std::cout << "读取失败:" << errMsg << std::endl;
}
);
return 0;
}
六、编译与运行
编译命令(GCC/Clang)
bash
g++ main.cpp -o promise-demo -std=c++11 -pthread
- 依赖:C++11及以上标准(支持
std::function、lambda、移动语义); -pthread:若使用std::thread模拟异步,需链接线程库。
运行效果
示例1运行输出:
发起请求...
成功:请求成功!返回数据:{name: 'MiniDataX'}
示例2运行输出:
商品总价:599.7元
示例3运行输出:
文件内容:数据库地址:localhost:3306
七、核心优势与扩展方向
核心优势
- 通用灵活:支持任意结果/错误类型,适配网络请求、文件读写、数据库操作等所有异步场景;
- 易用性强:链式调用语法简洁,类似前端Promise,降低异步编程门槛;
- 异常安全:自动捕获异步操作中的异常,避免程序崩溃;
- 无依赖:仅使用C++标准库,可直接集成到嵌入式、桌面、服务器等任何C++项目;
- 性能优秀:移动语义减少拷贝,无额外性能开销。
扩展方向
- 支持
catch方法 :单独注册失败回调(类似前端promise.catch),简化错误处理; - 支持
finally方法:无论成功/失败,都执行收尾操作(如释放资源); - 线程安全 :当前实现为单线程安全,若需多线程并发调用,可添加
std::mutex保护状态和回调; - 超时机制 :添加超时检测,超时后自动触发
reject; - Promise组合 :实现
Promise::all(所有Promise成功才返回)、Promise::race(第一个完成的Promise返回)。
八、总结
本文实现的C++ Promise组件,以"状态机+回调链"为核心,用极简代码实现了前端Promise的核心特性,同时兼顾C++的强类型和性能优势。该组件无需第三方依赖,用法简洁,可直接解决C++异步编程中的"回调地狱"和"状态管理混乱"问题。
无论是初学者学习异步编程思想,还是开发者在项目中处理异步场景,这个Promise组件都是一个实用的工具。后续可根据实际需求扩展线程安全、超时机制等功能,进一步提升其通用性。
如果你在使用中遇到问题或有优化建议,欢迎在评论区交流~