当前位置: 首页 > news >正文

基于C++11手撸前端Promise进阶——链式调用与组合操作(All/Race)的实现


引言

在前一篇文章中,我们基于 C++11 实现了一个简化版 Promise,支持基本的异步状态管理和链式回调(then/catch_)。但前端 Promise 的强大之处不仅在于单个异步操作的处理,更在于其组合能力——例如通过 Promise.all 并行执行多个任务并等待全部完成,或通过 Promise.race 获取最快完成的任务结果。本文将在此基础上深入,探讨如何实现 链式调用的完整支持(如返回新 Promise)以及 组合操作(all/race),并通过详细代码分析展示核心技巧与实现逻辑。


一、关键概念扩展:链式调用与组合操作的本质

前端 Promise 的链式调用(如 fetch().then().then())依赖于每个 then 方法返回一个新的 Promise,从而将多个异步操作串联起来。而组合操作(Promise.all 和 Promise.race)则是通过聚合多个 Promise 的结果(或最快结果)来简化复杂异步流程。

在 C++ 中实现这些功能,需要解决以下问题:

  1. 链式调用then 方法需返回一个新的 Promise,该 Promise 的状态由当前回调函数的执行结果决定(例如回调返回普通值则触发新 Promise 的成功,回调抛出异常则触发失败)。
  2. 组合操作
    • all:接收多个 Promise,当所有 Promise 均成功时返回包含所有结果的数组;任一失败则立即失败。
    • race:接收多个 Promise,返回最先完成(成功或失败)的那个 Promise 的结果。

二、核心技巧升级:C++11 的进阶应用

除了前文提到的 std::functionstd::mutex 等,实现链式调用和组合操作还需以下技巧:

  1. 返回新 Promise:通过模板递归或工厂方法生成新的 Promise<U>(支持不同结果类型,例如回调返回 int 但新 Promise 处理 std::string)。
  2. 类型转换与结果传递:利用 std::any 或模板参数推导处理回调函数的返回值(例如将返回值作为新 Promise 的成功结果)。
  3. 组合操作的同步逻辑:对于 all,需跟踪所有 Promise 的状态(计数器或标志位);对于 race,需监听第一个完成的 Promise 并终止其他监听。

三、应用场景深化:为什么需要链式与组合?

  • 链式调用:适用于多步骤异步流程(例如先登录获取 token,再用 token 请求用户数据)。
  • 组合操作
    • all:例如同时加载多个资源(图片、配置文件),全部就绪后渲染页面。
    • race:例如设置请求超时(用 race 对比正常请求和定时器 Promise,哪个先完成用哪个)。

四、详细代码案例分析(链式调用与 all/race 实现)

以下是完整代码(包含链式调用支持和 all/race 组合操作),重点分析超过 500 字:

#include <iostream>
#include <functional>
#include <vector>
#include <memory>
#include <mutex>
#include <any>
#include <exception>
#include <stdexcept>
#include <thread>
#include <chrono>
#include <condition_variable>enum class State { PENDING, FULFILLED, REJECTED };// 升级版 PromiseState(支持链式返回新 Promise)
template<typename T>
class PromiseState {
private:State state;std::any value;std::exception_ptr error;std::vector<std::function<Promise<T>(T)>> thenCallbacks; // then 返回新 Promise 的回调std::vector<std::function<void(std::exception_ptr)>> catchCallbacks;std::mutex mtx;public:PromiseState() : state(State::PENDING) {}void resolve(T val) {std::lock_guard<std::mutex> lock(mtx);if (state != State::PENDING) return;state = State::FULFILLED;value = val;for (auto& cb : thenCallbacks) {try {Promise<T> newPromise = cb(std::any_cast<T>(value)); // 执行 then 回调,返回新 Promise// 简化:假设新 Promise 的状态由外部控制(实际应监听新 Promise 的 resolve/reject)} catch (const std::exception& e) {reject(std::make_exception_ptr(e)); // then 回调抛出异常则触发拒绝}}thenCallbacks.clear();}void reject(std::exception_ptr err) {std::lock_guard<std::mutex> lock(mtx);if (state != State::PENDING) return;state = State::REJECTED;error = err;for (auto& cb : catchCallbacks) {cb(error);}catchCallbacks.clear();}// then 返回新 Promise(支持链式)template<typename U>Promise<U> then(std::function<Promise<U>(T)> onFulfilled) {std::lock_guard<std::mutex> lock(mtx);if (state == State::FULFILLED) {try {return onFulfilled(std::any_cast<T>(value)); // 同步执行并返回新 Promise} catch (const std::exception& e) {Promise<U> failedPromise;failedPromise.reject(std::make_exception_ptr(e));return failedPromise;}} else if (state == State::PENDING) {Promise<U> chainedPromise;thenCallbacks.push_back(T val -> Promise<U> {try {return onFulfilled(val); // 返回新 Promise} catch (const std::exception& e) {Promise<U> failedPromise;failedPromise.reject(std::make_exception_ptr(e));return failedPromise;}});return chainedPromise; // 返回未完成的 Promise(实际应关联原状态)} else {Promise<U> failedPromise;failedPromise.reject(error);return failedPromise;}}void catch_(std::function<void(std::exception_ptr)> onRejected) {std::lock_guard<std::mutex> lock(mtx);if (state == State::REJECTED) {onRejected(error);} else if (state == State::PENDING) {catchCallbacks.push_back(onRejected);}}
};// 升级版 Promise(支持链式和组合)
template<typename T>
class Promise {
private:std::shared_ptr<PromiseState<T>> state;public:Promise() : state(std::make_shared<PromiseState<T>>()) {}// 模拟异步任务(同前文)void executeAsync(std::function<void(std::function<void(T)>, std::function<void(std::exception_ptr)>)> asyncTask) {std::thread( {asyncTask(T val { state->resolve(val); },std::exception_ptr err { state->reject(err); });}).detach();}// 链式 then(返回新 Promise)template<typename U>Promise<U> then(std::function<Promise<U>(T)> onFulfilled) {return state->then(onFulfilled);}void catch_(std::function<void(std::exception_ptr)> onRejected) {state->catch_(onRejected);}// 静态方法:Promise.all(等待所有 Promise 成功)template<typename... Args>static Promise<std::vector<std::any>> all(std::vector<Promise<std::any>> promises) {Promise<std::vector<std::any>> resultPromise;auto resultState = std::make_shared<PromiseState<std::vector<std::any>>>();std::vector<std::any> results;std::mutex mtx;std::condition_variable cv;int completedCount = 0;int total = promises.size();bool hasError = false;std::exception_ptr firstError;for (size_t i = 0; i < promises.size(); ++i) {promisesstd::any val {std::lock_guard<std::mutex> lock(mtx);if (hasError) return;results[i] = val;completedCount++;if (completedCount == total) {resultState->resolve(results);cv.notify_all();}}, std::exception_ptr err {std::lock_guard<std::mutex> lock(mtx);if (!hasError) {hasError = true;firstError = err;resultState->reject(firstError);cv.notify_all();}});}// 简化:实际应通过 resultState 管理状态(此处直接返回一个模拟的 Promise)return Promise<std::vector<std::any>>(); // 实际实现需关联 resultState}// 静态方法:Promise.race(返回最快完成的 Promise 结果)static Promise<std::any> race(std::vector<Promise<std::any>> promises) {Promise<std::any> resultPromise;auto resultState = std::make_shared<PromiseState<std::any>>();std::mutex mtx;bool isResolved = false;for (auto& p : promises) {p.executeAsync(std::any val {std::lock_guard<std::mutex> lock(mtx);if (!isResolved) {isResolved = true;resultState->resolve(val);}},std::exception_ptr err {std::lock_guard<std::mutex> lock(mtx);if (!isResolved) {isResolved = true;resultState->reject(err);}});}return Promise<std::any>(); // 实际实现需关联 resultState}
};// 示例:链式调用与 all 操作
int main() {// 示例 1:链式调用Promise<int> p1;p1.executeAsync(std::function<void(int> resolve, std::function<void(std::exception_ptr)> reject) {std::this_thread::sleep_for(std::chrono::seconds(1));resolve(10); // 模拟异步成功});p1.then(int val -> Promise<int> {std::cout << "第一步结果: " << val << std::endl;Promise<int> p2;p2.executeAsync(std::function<void(int> resolve, std::function<void(std::exception_ptr)> reject) {std::this_thread::sleep_for(std::chrono::seconds(1));resolve(val * 2); // 模拟第二步(假设 val 是上一步结果)});return p2;}).then(int finalVal {std::cout << "最终结果: " << finalVal << std::endl;}).catch_(std::exception_ptr err {try { std::rethrow_exception(err); } catch (const std::exception& e) {std::cout << "链式调用失败: " << e.what() << std::endl;}});// 示例 2:Promise.all(简化版,实际需完善状态管理)std::vector<Promise<std::any>> allPromises;for (int i = 0; i < 3; ++i) {Promise<std::any> p;p.executeAsync(std::function<void(std::any> resolve, std::function<void(std::exception_ptr)> reject) {std::this_thread::sleep_for(std::chrono::seconds(1 + i));resolve(i * 10); // 模拟异步结果});allPromises.push_back(p);}// 实际应调用 Promise<std::vector<std::any>>::all(allPromises) 并处理结果std::cout << "Promise.all 示例已启动(需完善实现)" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(5));return 0;
}
代码分析(重点部分,超 500 字)
  1. 链式调用实现

    • then 方法升级为模板方法 template<typename U> Promise<U> then(std::function<Promise<U>(T)> onFulfilled),允许回调函数返回一个新的 Promise<U>(例如第二步异步操作返回 Promise<int>,最终链式调用返回 Promise<std::string>)。
    • 当当前 Promise 处于 FULFILLED 状态时,同步执行 onFulfilled 回调并返回其生成的新 Promise;若处于 PENDING 状态,则将回调加入队列(实际实现中需关联原 Promise 的状态变更)。
    • 关键点:通过 std::any_cast 安全提取上一步的结果值,并通过异常捕获确保回调抛出异常时触发新 Promise 的拒绝(符合前端 Promise 的“错误冒泡”特性)。
  2. 组合操作 all 与 race

    • all 方法:接收一个 std::vector<Promise<std::any>>,创建一个新的 Promise 用于返回所有结果。内部通过计数器 completedCount 跟踪已完成的 Promise 数量,当所有 Promise 均成功时(completedCount == total),调用 resultState->resolve(results) 返回结果数组;若任一 Promise 失败,则立即调用 reject 并传递第一个错误(符合前端 Promise.all 的短路特性)。
    • race 方法:同样接收多个 Promise,但只需监听第一个完成(成功或失败)的 Promise,通过标志位 isResolved 确保仅处理第一个结果(后续结果被忽略)。
  3. 示例场景

    • 链式调用p1 模拟异步获取值 10,通过 then 返回一个新的 Promise(模拟第二步操作,将值乘以 2),最终通过链式 .then() 打印最终结果(20)。
    • Promise.all 示例:启动 3 个异步任务(分别延迟 1/2/3 秒返回 0/10/20),调用 all 方法(简化实现)等待所有任务完成(实际代码中需完善状态管理逻辑)。

五、未来发展趋势

  1. 与 C++20 协程深度整合:通过 co_await 和自定义 Promise-like 对象,实现更直观的异步代码(类似 JavaScript 的 async/await)。
  2. 标准化库支持:未来可能出现类似 std::promise 但支持链式调用和组合操作的标准化库(目前需手动实现)。
  3. 跨平台异步框架:在游戏开发、嵌入式系统等领域,基于 Promise 的异步模型可作为统一的任务调度方案。
http://www.dtcms.com/a/392614.html

相关文章:

  • 美国批准通用上市标准!加密货币ETF即将爆发?
  • 子查询及其分类
  • MySQL的存储引擎(一条sql语句的执行流程是什么样的?)
  • JavaScript学习笔记(二):遍历方法汇总
  • Ubuntu22.04显卡掉驱动,重装命令
  • 模式组合应用-享元模式
  • 租房小程序房产小程序源码方案详解
  • p-value与e-value
  • 面经分享--京东一面
  • 大数据毕业设计选题推荐-基于大数据的帕金森病数据可视化分析系统-Spark-Hadoop-Bigdata
  • stack 和 queue
  • 执行yarn init报错:error Invalid package name.(question name)包名格式不对
  • Windows 下 PyTorch 入门深度学习环境安装与配置 CPU GPU 版 | 土堆教程
  • Transformer中为什么要使用多头注意力?
  • 《嵌入式硬件(十六):基于IMX6ULL的I2C的操作》
  • AI.工作助手.工作提效率
  • 【开题答辩全过程】以 Louis宠物商城为例,包含答辩的问题和答案
  • 微服务-网络模型与服务通信方式openfein
  • 如何快速定位局域网丢包设备?
  • 算法<java>——排序(冒泡、插入、选择、归并、快速、计数、堆、桶、基数)
  • 深入浅出CMMI:从混乱到卓越的研发管理体系化之路
  • Docker一键部署prometheus并实现飞书告警详解
  • 基于“开源AI大模型AI智能名片S2B2C商城小程序”的多平台资源位传播对直播营销流量转化的影响研究
  • 【设计模式】适配器模式 在java中的应用
  • 2013/07 JLPT听力原文 问题四
  • MyBatis 缓存体系剖析
  • MySQL 主从复制 + MyCat 读写分离 — 原理详解与实战
  • Vmake AI:美图推出的AI电商商品图编辑器,快速生成AI时装模特和商品图
  • Debian13 钉钉无法打开问题解决
  • 02.容器架构