Promise-CPP是一个开源的C++库,由xhawk18开发并维护,其GitHub仓库地址为
https://github.com/xhawk18/promise-cpp。该库旨在为C++开发者提供一种类似于JavaScript Promise/A+规范的异步编程模型,协助开发者更优雅地处理异步操作、回调地狱和错误处理问题。与C++标准库中的std::promise不同,Promise-CPP不是一个简单的未来值容器,而是借鉴了JavaScript中Promise的强劲功能,如链式调用、错误传播和多Promise协调等特性。

在现代软件开发中,异步编程已成为不可或缺的一部分,尤其是在网络编程、IO操作、多线程任务和事件驱动系统中。传统的C++异步编程往往依赖于回调函数,这容易导致代码嵌套过深、难以维护。Promise-CPP的出现填补了这一空白,它允许开发者使用Promise对象来表明异步操作的最终结果(成功或失败),并通过.then()、.fail()和.catch()等方法进行链式处理。这种设计不仅提高了代码的可读性,还增强了错误处理的鲁棒性。
Promise-CPP的核心思想是:一个Promise代表一个可能尚未完成的操作,它可以处于pending(待定)、fulfilled(已完成)或rejected(已拒绝)三种状态。一旦状态改变,它将触发相应的回调函数。该库特别适合那些习惯于JavaScript异步编程的开发者快速上手C++中的类似场景,同时也为纯C++开发者提供了全新的编程范式。
该库的灵感来源于JavaScript的Promise,但完全适应了C++的类型系统和性能要求。它支持模板化参数,确保类型安全,并能无缝集成Boost.Asio或其他IO服务库。Promise-CPP自2017年起开始开发,已被用于多个实际项目中,证明了其稳定性和实用性。作为一个轻量级库,它可以作为头文件库使用,无需复杂构建过程,这大大降低了入门门槛。
总之,Promise-CPP不仅仅是一个工具库,更是C++异步编程的一次革新。它让开发者从繁琐的回调管理中解放出来,转而专注于业务逻辑的实现。通过阅读本指南,您将全面了解如何在项目中引入和使用这个强劲的库。
Promise-CPP拥有多项独特特点,使其在众多C++异步库中脱颖而出:
这些特点使得Promise-CPP适用于从简单脚本到复杂服务器应用的各种场景。它不仅提升了代码质量,还减少了调试时间。根据仓库的星标和fork数量,该库已获得社区认可,许多开发者在GitHub issue中分享了使用经验。
Promise-CPP的模块可以根据API功能分为几个主要类别:全局函数、Promise类方法、Defer类方法、DeferLoop类方法以及辅助工具。每个模块都针对异步编程的不同方面设计,下面详细分类说明。
全局函数是创建和协调Promise的入口点,主要包括newPromise、resolve、reject、all、race等。这些函数不属于任何类,直接在promise命名空间中使用。
这些函数构成了Promise创建和组合的基础。
Promise类是库的核心,代表异步操作。它的方法主要用于链式处理结果。
Promise对象是不可变的,一旦settled状态固定。
Defer是Promise的“控制器”,用于内部resolve或reject Promise。
Defer一般在newPromise的回调中使用。
DeferLoop用于循环异步操作,如定时器或轮询。
这模块特别适合实现递归或迭代异步任务。
包括异常处理、多线程支持和集成工具,如setTimeout的Promise包装。
这些分类覆盖了库的所有功能,确保开发者能模块化使用。
Promise-CPP适用于多种异步编程场景,以下是详细列举:
在实际项目中,例如一个RESTful API服务器,可以用Promise-CPP处理用户认证、数据查询和响应生成,形成一个干净的链式流程。相比传统回调,这种方式减少了约30%的代码行数,并提高了可维护性。
另一个场景是大数据处理:将数据分块加载,每个块作为一个Promise,使用all等待全部加载后再聚合分析。这在云计算环境中特别高效。
总之,Promise-CPP的灵活性使其适用于从桌面应用到云服务的广泛领域,尤其在需要高并发和低延迟的系统中。
下面针对每个模块提供详细代码示例,直接嵌入文章中。示例基于仓库文档,并扩展说明以确保理解。所有代码假设包含<promise.hpp>头文件,并使用namespace promise。
newPromise是创建Promise的起点。以下示例创建一个简单的延迟Promise:
#include <promise.hpp>
#include <iostream>
#include <chrono>
#include <thread>
int main() {
promise::newPromise([](promise::Defer& d) {
std::thread([d]() {
std::this_thread::sleep_for(std::chrono::seconds(2));
d.resolve(42); // 2秒后resolve
}).detach();
}).then([](int value) {
std::cout << "Resolved with: " << value << std::endl;
}).fail([](const std::exception& e) {
std::cout << "Rejected: " << e.what() << std::endl;
});
std::this_thread::sleep_for(std::chrono::seconds(3)); // 等待完成
return 0;
}这个示例演示了如何在子线程中执行异步操作,并通过Defer控制Promise状态。运行后,输出"Resolved with: 42"。
resolve用于立即成功,reject用于立即失败:
#include <promise.hpp>
#include <iostream>
int main() {
auto p1 = promise::resolve("Success!");
p1.then([](const std::string& msg) {
std::cout << msg << std::endl;
});
auto p2 = promise::reject(std::runtime_error("Failure"));
p2.fail([](const std::exception& e) {
std::cout << e.what() << std::endl;
});
return 0;
}输出:"Success!" 和 "Failure"。这在测试中超级有用,可以模拟不同结果。
all等待多个Promise:
#include <promise.hpp>
#include <iostream>
#include <vector>
int main() {
std::vector<promise::Promise> promises;
promises.push_back(promise::resolve(1));
promises.push_back(promise::resolve(2));
promises.push_back(promise::newPromise([](promise::Defer& d) {
d.resolve(3);
}));
promise::all(promises).then([](const std::tuple<int, int, int>& results) {
std::cout << "All resolved: " << std::get<0>(results) << ", " << std::get<1>(results) << ", " << std::get<2>(results) << std::endl;
}).fail([](const std::exception& e) {
std::cout << "One failed: " << e.what() << std::endl;
});
return 0;
}如果所有Promise成功,输出"All resolved: 1, 2, 3"。如果任意一个reject,整个all reject。
race返回第一个完成的:
#include <promise.hpp>
#include <iostream>
#include <chrono>
#include <thread>
int main() {
auto p1 = promise::newPromise([](promise::Defer& d) {
std::this_thread::sleep_for(std::chrono::seconds(1));
d.resolve("First");
});
auto p2 = promise::newPromise([](promise::Defer& d) {
std::this_thread::sleep_for(std::chrono::seconds(2));
d.resolve("Second");
});
promise::race({p1, p2}).then([](const std::string& winner) {
std::cout << "Winner: " << winner << std::endl;
});
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}输出"Winner: First",由于p1先完成。
then处理成功结果,并支持链式:
#include <promise.hpp>
#include <iostream>
int main() {
promise::newPromise([](promise::Defer& d) {
d.resolve(10);
}).then([](int x) {
return x * 2; // 返回值成为下一个then的参数
}).then([](int y) {
std::cout << "Result: " << y << std::endl; // 输出20
});
return 0;
}这展示了链式计算的优势。
fail处理错误:
#include <promise.hpp>
#include <iostream>
int main() {
promise::newPromise([](promise::Defer& d) {
d.reject(std::runtime_error("Error occurred"));
}).then([](int) {
// 不会执行
}).fail([](const std::exception& e) {
std::cout << "Caught: " << e.what() << std::endl;
});
return 0;
}输出"Caught: Error occurred"。catch是fail的别名。
finally总是执行:
#include <promise.hpp>
#include <iostream>
int main() {
promise::resolve(1).then([](int) {
std::cout << "Then" << std::endl;
}).finally([] {
std::cout << "Finally" << std::endl;
});
promise::reject("Error").fail([](const std::string&) {
std::cout << "Fail" << std::endl;
}).finally([] {
std::cout << "Finally again" << std::endl;
});
return 0;
}输出"Then Finally Fail Finally again"。
tap插入副作用:
#include <promise.hpp>
#include <iostream>
int main() {
promise::resolve(5).tap([](int x) {
std::cout << "Tap: " << x << std::endl; // 输出5,但不改变值
}).then([](int x) {
std::cout << "Then: " << x << std::endl; // 仍是5
});
return 0;
}用于日志记录而不影响链。
Defer控制Promise:
#include <promise.hpp>
#include <iostream>
#include <thread>
int main() {
auto defer = promise::newDefer(); // 创建Defer
auto p = defer.promise(); // 获取Promise
p.then([](int val) {
std::cout << "Resolved: " << val << std::endl;
});
std::thread([defer]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
defer.resolve(100);
}).detach();
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}这允许外部控制Promise状态。
DeferLoop用于循环:
#include <promise.hpp>
#include <iostream>
#include <chrono>
#include <thread>
int main() {
promise::newLoopPromise([](promise::DeferLoop& loop, int count) {
if (count >= 5) {
loop.resolve("Done");
return;
}
std::cout << "Iteration: " << count << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
loop.recur(count + 1); // 继续循环
}, 0).then([](const std::string& result) {
std::cout << result << std::endl;
});
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}输出Iteration 0到4,然后"Done"。这模拟异步轮询。
基于仓库示例:
#include <promise.hpp>
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <iostream>
using tcp = boost::asio::ip::tcp;
namespace http = boost::beast::http;
promise::Promise download(boost::asio::io_context& ioc, const std::string& url) {
return promise::newPromise([&ioc, url](promise::Defer& d) {
// 简化版HTTP下载逻辑
// ... (实际代码需实现连接、发送请求、接收响应)
// 成功时 d.resolve(response);
// 失败时 d.reject(error);
});
}
int main() {
boost::asio::io_context ioc;
download(ioc, "http://www.example.com/")
.then([&ioc]() {
return download(ioc, "http://another.com/");
}).then([]() {
std::cout << "All downloads complete" << std::endl;
}).fail([](const std::exception& e) {
std::cout << "Download failed: " << e.what() << std::endl;
});
ioc.run();
return 0;
}这展示了链式下载多个网站。
仓库示例:
#include <promise.hpp>
#include <boost/asio.hpp>
#include <iostream>
promise::Promise myDelay(boost::asio::io_service& io, uint64_t time_ms) {
return promise::newPromise([&io, time_ms](promise::Defer& d) {
auto timer = std::make_shared<boost::asio::deadline_timer>(io);
timer->expires_from_now(boost::posix_time::milliseconds(time_ms));
timer->async_wait([d, timer](const boost::system::error_code& ec) {
if (ec) d.reject(ec.message());
else d.resolve();
});
});
}
int main() {
boost::asio::io_service io;
myDelay(io, 1000).then([]() {
std::cout << "1 second passed" << std::endl;
return myDelay(io, 2000);
}).then([]() {
std::cout << "Another 2 seconds" << std::endl;
});
io.run();
return 0;
}链式定时器,输出相应消息。
Promise-CPP支持C++异常。如果在then中抛出异常,它会转换为reject:
promise::resolve(1).then([](int) {
throw std::runtime_error("Boom!");
}).fail([](const std::exception& e) {
std::cout << e.what() << std::endl; // 输出"Boom!"
});多线程时,需要小心共享Promise,使用mutex保护。
关于Promise拷贝:Promise是可拷贝的,内部使用shared_ptr。
未处理拒绝:库会输出警告,避免沉默错误。
Promise-CPP开启了C++异步编程的新时代。通过本指南,您已掌握其核心用法。提议从简单示例开始,逐步集成到项目中。更多细节见GitHub仓库。