C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ Promise

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

作者:郝学胜-神的一滴

本文将从一个手写的 C++ Promise实现(基于 C++11)出发,分析其工作原理,并与 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);
};

构造函数

CProimse()
    : m_state(CProimseState::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);
        }
    }
}

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);
        }
    }
}

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;
}

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);
    }
}

链式调用

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

proimse->then([](int ele) -> void { 
    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) 状态管理

(2) 回调注册与执行

(3) 异步支持

(4) 链式调用

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

(2)std::promise

总结与展望

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

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

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

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

您可能感兴趣的文章:
阅读全文