开发者

基于C++11手撸前端Promise及应用与优势

开发者 https://www.devze.com 2025-10-24 10:56 出处:网络 作者: 郝学胜-神的一滴
目录引言前端Promise的应用与优势常见应用场景并发请求Promise 解决的问题手写 C++ Promise 实现类结构与成员变量构造函数resolve 方法reject 方法then 方法onCatch 方法链式调用使用示例std::promise与CProimse对比
目录
  • 引言
  • 前端Promise的应用与优势
    • 常见应用场景
    • 并发请求
    • Promise 解决的问题
  • 手写 C++ Promise 实现
    • 类结构与成员变量
    • 构造函数
    • resolve 方法
    • reject 方法
    • then 方法
    • onCatch 方法
    • 链式调用
    • 使用示例
  • std::promise与CProimse对比
    • 1. 基础功能对比
    • 2. 实现细节对比
      • (1) 状态管理
      • (2) 回调注册与执行
      • (3) 异步支持
      • (4) 链式调用
    • 3. 代码示例对比
      • (1)CProimse示例
      • (2)std::promise示例
    • 4. 优缺点分析
      • (1)CProimse
      • (2)std::promise
  • 总结与展望

    引言

    在前端开发中,Promise 是处理异步操作的重要工具。它通过将异步操作封装在 Promise 实例中,解决了传统回调地狱的问题,提高了代码的可读性和可维护性。Promise 的概念并非前端独有,在 C++11 标准中也引入了 std::promise,用于实现类似的功能。

    本文将从一个手写的 C++ Promise 实现(基于 C++11)出发,分析其工作原理,并与 std::promise 进行对比,探讨两者的异同点以及适用场景。

    前端Promise的应用与优势

    常见应用场景

    网络请求

    Promise 可以用于处理 AJAX 请求,简化异步数据获取的逻辑。

    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 解决的问题

    1. 回调地狱:通过链式调用,Promise 解决了传统回调嵌套导致的代码难以阅读和维护的问题【6†source】。
    2. 错误处理:Promise 提供了统一的错误处理机制,通过 catch 方法可以集中处理所有异步操作中的错误【1†source】。
    3. 代码可读性:Promise 使得异步代码的逻辑更加清晰,符合同步代码的书写习惯【6†source】。
    4. 并发控制:通过 Promise.allPromise.race,可以方便地控制多个异步操作的执行顺序和结果【5†source】。

    手写 C++ Promise 实现

    类结构与成员变量

    template<typename Element>
    class CProimse 
    {
    private:
        using Resolve = std::function<void(Element)>;
        using Reject = std::function<void(const std::string&)>;
    private:
        Element m_element;      /**< 异步操作的结果 */
        std::string m_reason;   /**< 拒绝的原因 */
        CProimseState m_state;  /**< 当前状态 */
        std::list<Resolve> m_resolves; /**< 成功回调函数列表 */
        std::list<Reject> m_rejects;   /**< 失败回调函数列表 */
    public:
        CProimse();
        void reject(const std::string& reason);
        void resolve(Element element); 
        void onCatch(const Reject& rej);
        CProimse* then(const Resolve& res);
    };
    • ResolveReject :定义了成功和失败回调函数的类型。
    • m_elementm_reason :分别存储 Promise 的结果和拒绝原因。
    • m_state :表示 Promise 的当前状态,初始状态为 PENDING。
    • m_resolvesm_rejects :存储注册的成功和失败回调函数列表。
    fNjrigq

    构造函数

    CProimse()
        : m_state(CProimseState::PENDING)
    {
    }
    
    • 作用:初始化 Promise 的状态为 PENDING。

    resolve 方法

    void resolve(Element element) 
    {
        m_element = element;
        if (m_state == CProimseState::PENDING)
        {
            m_state = CProimseState::FULFILLED;
            for (Resolve res : m_resolves)
            {
                res(element);
            }
        }
    }
    
    • 作用:将 Promise 的状态设置为 FULFILLED,并执行所有注册的成功回调函数。

    reject 方法

    void reject(const std::string& reason)
    {
        m_reason = reason;
        if (m_state == CProimseState::PENDING)
        {
            m_state = CProimseState::REJECTED;
            for (Reject rej : m_rejects)
            {
                rej(reason);
            }
        }
    }
    
    • 作用:将 Promise 的状态设置为 REJECTED,并执行所有注册的失败回调函数。

    then 方法

    CProimse* then(const Resolve& res)
    {
        if (m_state == CProimseState::FULFILLED)
        {
            res(m_element);
        }
        else if (m_state == CProimseState::PENDING)
        {
            m_resolves.push_back(res);
        }
        return this;
    }
    
    • 作用:注册一个成功回调函数。如果 Promise 已经完成,则立即执行回调;否则,将回调添加到成功回调列表中。

    onCatch 方法

    void onCatch(const Reject& rej)
    {
        if (m_state == CProimseState::REJECTED)
        {
            rej(m_reason);
        }
        else if (m_state == CProimseState::PENDING)
        {
            m_rejects.push_back(rej);
        }
    }
    
    • 作用:注册一个失败回调函数。如果 Promise 已经被拒绝编程客栈,则立即执行回调;否则,将回调添加到失败回调列表中。

    链式调用

    通过 thenonCatch 方法,可以实现链式调用,使得异步操作的处理更加简洁和直观。

    proimse->then([](int ele) -> void {php 
        std::cout << ele << std::endl; 
    })->onCatch([](const std::string& reason) -> void {
        std::cout << reason << std::endl;
    });
    

    使用示例

    CProimse<int>* proimse = new CProimse<int>();
    proimse->then([](int ele) -> void { 
        std::cout << ele << std::endl; 
    })->onCatch([](const std::string& reason) -> void {
        std::cout << reason << std::endl;
    });
    proimse->reject("网络异常!!!");

    std::promise与CProimse对比

    1. 基础功能对比

    功能CProimse 实现std::promise
    状态管理手动实现标准库实现
    回调注册与执行手动实现标准库实现
    异步支持需结合线程内置支持
    链式调用支持不支持

    2. 实现细节对比

    (1) 状态管理

    • CProimse :通过自定义枚举 CProimseState 管理状态。
    • std::promise :状态管理由标准库实现,用户无需关注底层细节。

    (2) 回调注册与执行

    • CProimse :手动维护回调队列,通过 thenonCatch 方法注册回编程客栈调。
    • std::promise :通过 std::futurestd::promise 配合,回调通过 futureget 方法触发。

    (3) 异步支持

    • CProimse :需要结合 std::thread 或其他异步框架实现异步操作。
    • std::promise :内置支持异步操作,通常与 std::asyncstd::thread 结合使用。

    (4) 链式调用

    • CProimse :支持链式调用,通过返回 this 实现。
    • std::promise :不支持链式调用,无法直接链式注册回调。

    3. 代码示例对比

    (1)CProimse示例

    CProimse<int>* proimse = new CProimse<int>();
    proimse->then([](int ele) -> void { 
        std::cout << ele << std::endl; 
    })->onCatch([](const std::string& reason) -> void {
        std::cout << reason << std::endl;
    });
    proimse->reject("网络异常!!!");

    (2)std::promise示例

    #include <future>
    #include <thread>
    #include <IOStream>
    int main()
    {
        std::promise<int> prom;
        std::future<int> fut = prom.get_future();
        // 异步操作
        std::thread([&prom]() {
            // 模拟网络请求
            std::this_thread::sleep_for(std::chrono::seconds(1));
            prom.set_value(42);
        }).detach();
        // 注册回调
        fut.then([](std::future<int> fut) {
            try {
                int result = fut.get();
                std::cout << "结果: " << result << std::endl;
            } catch (const std::exception& e) {
                std::cout << "错误: " << e.what() << std::endl;
            }
        });
        // 主线程阻塞等待
        std::this_thread::sleep_for(std::chrono::seconds(2));
        return 0;
    }

    4. 优缺点分析

    (1)CProimse

    • 优点
      • 代码简洁,易于理解。
      • 支持链式调用,使用方式类似前端 Promise。
      • 可以作为学习 Promise 实现原理的示例。
    • 缺点
      • 不支持内置异步操作,需要结合线程实现。
      • 功能较为基础,缺乏 std::promise 的高级特性(如 then 的链式返回)。

    (2)std::promise

    • 优点
      • 内置异步支持,与 std::future 配合使用,功能强大。
      • 标准库实现,性能优化和稳定性有保障。
      • 支持 C++11 及以上标准,兼容性好。
    • 缺点
      • 使用方式较为复杂,缺乏链式调用的支持。
      • 回调机制不够灵活,无法像前端 Promise 那样优雅地处理异步流程。

    总结与展望

    通过手写 CProimse,我们可以深入理解 Promise 的实现原理,包括状态管理、回调注册与执行等核心机制。然而,在实际开发中,std::promise 仍然是更好的选择,因为fNjrigq它提供了更强大的功能和更好的性能保障。

    对于开发者来说,理解 std::promise 的工作原理以及其与手写实现的异同点,有助于更好地选择合适的工具来处理异步操作。同时,手写实现虽然功能有限,但作为学习和探索的工具,仍然具有重要的价值。

    希望本文能够帮助读者更好地理解 Promise 的实现原理,并在实际开发中做出更明智的选择。

    到此这篇关于基于C++11手撸前端Promise及应用与优势的文章就介绍到这了,更多相关C++ Promise内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号