C++手写Promise实现与std::promise对比
目录
引言
在前端开发中,Promise作为处理异步操作的核心工具,显著提升了代码的可读性和可维护性。其概念并非局限于JavaScript领域,在C++11标准中也引入了std::promise,为开发者提供了类似的异步处理机制。本文将基于C++11实现一个手写Promise类(命名为CPromise),深入剖析其设计原理,并通过与std::promise的对比,探讨两者的异同点及适用场景。文章旨在帮助开发者理解异步编程的本质,并为实际项目提供参考。
前端Promise的应用与优势
Promise在前端开发中广泛应用于处理异步任务,其优势主要体现在以下几个方面:
常见应用场景
- 网络请求:Promise简化了AJAX请求的逻辑,例如使用
fetchAPI:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log('获取到数据:', data);
})
.catch(error => {
console.error('请求失败:', error);
});
- 定时器处理:Promise使定时器代码更直观:
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
timeout(1000)
.then(() => {
console.log('1秒后执行');
});
- 并发请求:通过
Promise.all管理多个异步任务:
const promise1 = fetch('https://api.example.com/data1');
const promise2 = fetch('https://api.example.com/data2');
Promise.all([promise1, promise2])
.then(responses => {
const [data1, data2] = responses.map(response => response.json());
return Promise.all([data1, data2]);
})
.then(([data1, data2]) => {
console.log('两个数据都获取成功:', data1, data2);
})
.catch(error => {
console.error('至少一个请求失败:', error);
});
Promise解决的问题
- 回调地狱:链式调用替代嵌套回调,提升代码结构清晰度。
- 错误处理:统一通过
.catch()捕获异常,避免分散的错误处理逻辑。 - 并发控制:
Promise.all和Promise.race简化多任务协同。
手写C++ Promise实现
以下基于C++11实现一个简化版Promise类CPromise,支持基本异步操作。
类结构与成员变量
template<typename T>
class CPromise {
private:
// 定义回调函数类型
using ResolveHandler = std::function<void(T)>;
using RejectHandler = std::function<void(const std::string&)>;
// 状态枚举
enum class PromiseState { PENDING, FULFILLED, REJECTED };
T m_value; // 存储结果值
std::string m_reason; // 拒绝原因
PromiseState m_state; // 当前状态
std::list<ResolveHandler> m_resolves; // 成功回调列表
std::list<RejectHandler> m_rejects; // 失败回调列表
public:
CPromise();
void resolve(T value);
void reject(const std::string& reason);
CPromise* then(const ResolveHandler& handler);
void onCatch(const RejectHandler& handler);
};
构造函数
初始化状态为PENDING:
template<typename T>
CPromise<T>::CPromise() : m_state(PromiseState::PENDING) {}
resolve方法
将状态设为FULFILLED并执行回调:
template<typename T>
void CPromise<T>::resolve(T value) {
if (m_state == PromiseState::PENDING) {
m_value = value;
m_state = PromiseState::FULFILLED;
for (auto& handler : m_resolves) {
handler(value); // 执行所有成功回调
}
}
}
reject方法
将状态设为REJECTED并执行回调:
template<typename T>
void CPromise<T>::reject(const std::string& reason) {
if (m_state == PromiseState::PENDING) {
m_reason = reason;
m_state = PromiseState::REJECTED;
for (auto& handler : m_rejects) {
handler(reason); // 执行所有失败回调
}
}
}
then方法
注册成功回调,支持链式调用:
template<typename T>
CPromise<T>* CPromise<T>::then(const ResolveHandler& handler) {
if (m_state == PromiseState::FULFILLED) {
handler(m_value); // 立即执行
} else if (m_state == PromiseState::PENDING) {
m_resolves.push_back(handler); // 添加到队列
}
return this; // 返回自身以支持链式调用
}
onCatch方法
注册失败回调:
template<typename T>
void CPromise<T>::onCatch(const RejectHandler& handler) {
if (m_state == PromiseState::REJECTED) {
handler(m_reason); // 立即执行
} else if (m_state == PromiseState::PENDING) {
m_rejects.push_back(handler); // 添加到队列
}
}
链式调用示例
CPromise<int>* promise = new CPromise<int>();
promise->then([](int value) {
std::cout << "结果: " << value << std::endl;
})->onCatch([](const std::string& reason) {
std::cout << "错误: " << reason << std::endl;
});
promise->reject("网络异常!!!");
std::promise与CPromise对比
基础功能对比
| 功能 | CPromise实现 | std::promise |
|---|---|---|
| 状态管理 | 手动实现 | 标准库实现 |
| 回调注册与执行 | 手动队列 | 通过future关联 |
| 异步支持 | 需结合线程 | 内置线程安全 |
| 链式调用 | 支持 | 不支持 |
实现细节对比
-
状态管理
CPromise:自定义状态枚举(PENDING, FULFILLED, REJECTED),需手动维护。std::promise:内部管理状态,通过std::future获取结果。
-
回调注册
CPromise:使用std::list存储回调,需手动遍历执行。std::promise:通过set_value或set_exception触发关联的future。
-
线程安全
CPromise:非线程安全,需外部同步(如互斥锁)。std::promise:线程安全,可跨线程操作。
-
链式调用
CPromise:通过返回this实现链式调用。std::promise:不支持链式,需配合std::future使用。
代码示例对比
- CPromise示例
CPromise<std::string>* p = new CPromise<std::string>();
p->then([](std::string s) { std::cout << s; });
p->resolve("成功!");
- std::promise示例
std::promise<std::string> prom;
std::future<std::string> fut = prom.get_future();
std::thread t([&] { prom.set_value("结果"); });
t.join();
std::cout << fut.get(); // 输出"结果"
优缺点分析
-
CPromise
- 优点:轻量级、支持链式调用、易于定制扩展。
- 缺点:非线程安全、需手动管理状态。
-
std::promise
- 优点:线程安全、标准库支持、与
std::future无缝集成。 - 缺点:不支持链式调用、使用稍复杂。
- 优点:线程安全、标准库支持、与
新增内容:线程安全与性能优化
为提升CPromise的实用性,可添加线程安全机制:
#include <mutex>
template<typename T>
class SafePromise : public CPromise<T> {
private:
std::mutex m_mtx;
public:
void resolve(T value) {
std::lock_guard<std::mutex> lock(m_mtx);
CPromise<T>::resolve(value);
}
// 类似实现reject等方法
};
性能方面,std::promise因标准库优化通常更高效,但CPromise在轻量场景下开销更低。
总结与展望
本文通过手写CPromise类,深入解析了Promise的核心机制,并对比了其与std::promise的差异。未来可扩展功能如Promise.all实现,或集成到Qt等框架中。开发者应根据需求选择:CPromise适合简单异步场景,而std::promise更适用于多线程环境。异步编程是现代化开发的基石,掌握其原理将显著提升代码质量。
版权声明:本文采用CC 4.0 BY-SA协议,转载请注明出处。
标签:C++、前端、异步编程、Promise、std::promise
专栏:基于Qt的新概念浏览器
更多推荐

所有评论(0)