基于C++11手?jǐn)]前端Promise及應(yīng)用與優(yōu)勢(shì)
引言
在前端開發(fā)中,Promise 是處理異步操作的重要工具。它通過(guò)將異步操作封裝在 Promise 實(shí)例中,解決了傳統(tǒng)回調(diào)地獄的問(wèn)題,提高了代碼的可讀性和可維護(hù)性。Promise 的概念并非前端獨(dú)有,在 C++11 標(biāo)準(zhǔn)中也引入了 std::promise,用于實(shí)現(xiàn)類似的功能。
本文將從一個(gè)手寫的 C++ Promise 實(shí)現(xiàn)(基于 C++11)出發(fā),分析其工作原理,并與 std::promise 進(jìn)行對(duì)比,探討兩者的異同點(diǎn)以及適用場(chǎng)景。
前端Promise的應(yīng)用與優(yōu)勢(shì)
常見應(yīng)用場(chǎng)景
網(wǎng)絡(luò)請(qǐng)求
Promise 可以用于處理 AJAX 請(qǐng)求,簡(jiǎn)化異步數(shù)據(jù)獲取的邏輯。
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log('獲取到數(shù)據(jù):', data);
})
.catch(error => {
console.error('請(qǐng)求失敗:', error);
});
定時(shí)器
Promise 還可以用于處理定時(shí)器,使代碼更加直觀。
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
timeout(1000)
.then(() => {
console.log('1秒后執(zhí)行');
});并發(fā)請(qǐng)求
使用 Promise.all 可以同時(shí)處理多個(gè)異步請(qǐng)求。
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('兩個(gè)數(shù)據(jù)都獲取成功:', data1, data2);
})
.catch(error => {
console.error('至少一個(gè)請(qǐng)求失敗:', error);
});Promise 解決的問(wèn)題
- 回調(diào)地獄:通過(guò)鏈?zhǔn)秸{(diào)用,Promise 解決了傳統(tǒng)回調(diào)嵌套導(dǎo)致的代碼難以閱讀和維護(hù)的問(wèn)題【6†source】。
- 錯(cuò)誤處理:Promise 提供了統(tǒng)一的錯(cuò)誤處理機(jī)制,通過(guò)
catch方法可以集中處理所有異步操作中的錯(cuò)誤【1†source】。 - 代碼可讀性:Promise 使得異步代碼的邏輯更加清晰,符合同步代碼的書寫習(xí)慣【6†source】。
- 并發(fā)控制:通過(guò)
Promise.all和Promise.race,可以方便地控制多個(gè)異步操作的執(zhí)行順序和結(jié)果【5†source】。
手寫 C++ Promise 實(shí)現(xiàn)
類結(jié)構(gòu)與成員變量
template<typename Element>
class CProimse
{
private:
using Resolve = std::function<void(Element)>;
using Reject = std::function<void(const std::string&)>;
private:
Element m_element; /**< 異步操作的結(jié)果 */
std::string m_reason; /**< 拒絕的原因 */
CProimseState m_state; /**< 當(dāng)前狀態(tài) */
std::list<Resolve> m_resolves; /**< 成功回調(diào)函數(shù)列表 */
std::list<Reject> m_rejects; /**< 失敗回調(diào)函數(shù)列表 */
public:
CProimse();
void reject(const std::string& reason);
void resolve(Element element);
void onCatch(const Reject& rej);
CProimse* then(const Resolve& res);
};Resolve和Reject:定義了成功和失敗回調(diào)函數(shù)的類型。m_element和m_reason:分別存儲(chǔ) Promise 的結(jié)果和拒絕原因。m_state:表示 Promise 的當(dāng)前狀態(tài),初始狀態(tài)為 PENDING。m_resolves和m_rejects:存儲(chǔ)注冊(cè)的成功和失敗回調(diào)函數(shù)列表。
構(gòu)造函數(shù)
CProimse()
: m_state(CProimseState::PENDING)
{
}
- 作用:初始化 Promise 的狀態(tài)為 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 的狀態(tài)設(shè)置為 FULFILLED,并執(zhí)行所有注冊(cè)的成功回調(diào)函數(shù)。
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 的狀態(tài)設(shè)置為 REJECTED,并執(zhí)行所有注冊(cè)的失敗回調(diào)函數(shù)。
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;
}
- 作用:注冊(cè)一個(gè)成功回調(diào)函數(shù)。如果 Promise 已經(jīng)完成,則立即執(zhí)行回調(diào);否則,將回調(diào)添加到成功回調(diào)列表中。
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);
}
}
- 作用:注冊(cè)一個(gè)失敗回調(diào)函數(shù)。如果 Promise 已經(jīng)被拒絕,則立即執(zhí)行回調(diào);否則,將回調(diào)添加到失敗回調(diào)列表中。
鏈?zhǔn)秸{(diào)用
通過(guò) then 和 onCatch 方法,可以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,使得異步操作的處理更加簡(jiǎn)潔和直觀。
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("網(wǎng)絡(luò)異常!!!");std::promise與CProimse對(duì)比
1. 基礎(chǔ)功能對(duì)比
| 功能 | CProimse 實(shí)現(xiàn) | std::promise |
|---|---|---|
| 狀態(tài)管理 | 手動(dòng)實(shí)現(xiàn) | 標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn) |
| 回調(diào)注冊(cè)與執(zhí)行 | 手動(dòng)實(shí)現(xiàn) | 標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn) |
| 異步支持 | 需結(jié)合線程 | 內(nèi)置支持 |
| 鏈?zhǔn)秸{(diào)用 | 支持 | 不支持 |
2. 實(shí)現(xiàn)細(xì)節(jié)對(duì)比
(1) 狀態(tài)管理
CProimse:通過(guò)自定義枚舉CProimseState管理狀態(tài)。std::promise:狀態(tài)管理由標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn),用戶無(wú)需關(guān)注底層細(xì)節(jié)。
(2) 回調(diào)注冊(cè)與執(zhí)行
CProimse:手動(dòng)維護(hù)回調(diào)隊(duì)列,通過(guò)then和onCatch方法注冊(cè)回調(diào)。std::promise:通過(guò)std::future與std::promise配合,回調(diào)通過(guò)future的get方法觸發(fā)。
(3) 異步支持
CProimse:需要結(jié)合std::thread或其他異步框架實(shí)現(xiàn)異步操作。std::promise:內(nèi)置支持異步操作,通常與std::async或std::thread結(jié)合使用。
(4) 鏈?zhǔn)秸{(diào)用
CProimse:支持鏈?zhǔn)秸{(diào)用,通過(guò)返回this實(shí)現(xiàn)。std::promise:不支持鏈?zhǔn)秸{(diào)用,無(wú)法直接鏈?zhǔn)阶?cè)回調(diào)。
3. 代碼示例對(duì)比
(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("網(wǎng)絡(luò)異常!!!");(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]() {
// 模擬網(wǎng)絡(luò)請(qǐng)求
std::this_thread::sleep_for(std::chrono::seconds(1));
prom.set_value(42);
}).detach();
// 注冊(cè)回調(diào)
fut.then([](std::future<int> fut) {
try {
int result = fut.get();
std::cout << "結(jié)果: " << result << std::endl;
} catch (const std::exception& e) {
std::cout << "錯(cuò)誤: " << e.what() << std::endl;
}
});
// 主線程阻塞等待
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}4. 優(yōu)缺點(diǎn)分析
(1)CProimse
- 優(yōu)點(diǎn):
- 代碼簡(jiǎn)潔,易于理解。
- 支持鏈?zhǔn)秸{(diào)用,使用方式類似前端 Promise。
- 可以作為學(xué)習(xí) Promise 實(shí)現(xiàn)原理的示例。
- 缺點(diǎn):
- 不支持內(nèi)置異步操作,需要結(jié)合線程實(shí)現(xiàn)。
- 功能較為基礎(chǔ),缺乏
std::promise的高級(jí)特性(如then的鏈?zhǔn)椒祷兀?/li>
(2)std::promise
- 優(yōu)點(diǎn):
- 內(nèi)置異步支持,與
std::future配合使用,功能強(qiáng)大。 - 標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn),性能優(yōu)化和穩(wěn)定性有保障。
- 支持 C++11 及以上標(biāo)準(zhǔn),兼容性好。
- 內(nèi)置異步支持,與
- 缺點(diǎn):
- 使用方式較為復(fù)雜,缺乏鏈?zhǔn)秸{(diào)用的支持。
- 回調(diào)機(jī)制不夠靈活,無(wú)法像前端 Promise 那樣優(yōu)雅地處理異步流程。
總結(jié)與展望
通過(guò)手寫 CProimse,我們可以深入理解 Promise 的實(shí)現(xiàn)原理,包括狀態(tài)管理、回調(diào)注冊(cè)與執(zhí)行等核心機(jī)制。然而,在實(shí)際開發(fā)中,std::promise 仍然是更好的選擇,因?yàn)樗峁┝烁鼜?qiáng)大的功能和更好的性能保障。
對(duì)于開發(fā)者來(lái)說(shuō),理解 std::promise 的工作原理以及其與手寫實(shí)現(xiàn)的異同點(diǎn),有助于更好地選擇合適的工具來(lái)處理異步操作。同時(shí),手寫實(shí)現(xiàn)雖然功能有限,但作為學(xué)習(xí)和探索的工具,仍然具有重要的價(jià)值。
希望本文能夠幫助讀者更好地理解 Promise 的實(shí)現(xiàn)原理,并在實(shí)際開發(fā)中做出更明智的選擇。
到此這篇關(guān)于基于C++11手?jǐn)]前端Promise及應(yīng)用與優(yōu)勢(shì)的文章就介紹到這了,更多相關(guān)C++ Promise內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VSCode Linux的C++代碼格式化配置的實(shí)現(xiàn)
動(dòng)格式化代碼容易出現(xiàn)錯(cuò)誤,特別是當(dāng)代碼量較大時(shí),使用自動(dòng)格式化可以減少這種錯(cuò)誤的風(fēng)險(xiǎn),本文主要介紹了VSCode Linux的C++代碼格式化配置的實(shí)現(xiàn),感興趣的可以了解一下2023-10-10
C++實(shí)現(xiàn)批量提取PDF內(nèi)容
這篇文章主要為大家詳細(xì)介紹了如何使用C++批量提取PDF里文字內(nèi)容并導(dǎo)出到表格以及批量給?PDF?文件改名,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02
C語(yǔ)言學(xué)生信息管理系統(tǒng)小項(xiàng)目
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言學(xué)生信息管理系統(tǒng)小項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
C語(yǔ)言利用數(shù)組和文件實(shí)現(xiàn)登錄注冊(cè)功能
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言利用數(shù)組和文件實(shí)現(xiàn)登錄注冊(cè)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
詳解如何實(shí)現(xiàn)C++虛函數(shù)調(diào)用匯編代碼
多態(tài)是C++中最重要的特性之一,對(duì)虛函數(shù)的調(diào)用在C++代碼中是隨處可見的,本篇文章我們?cè)敿?xì)探討一下,感興趣的朋友快來(lái)看看吧2021-11-11
C++中內(nèi)存池的簡(jiǎn)單原理及實(shí)現(xiàn)詳解
內(nèi)存池的思想是,在真正使用內(nèi)存之前,預(yù)先申請(qǐng)分配一定數(shù)量、大小預(yù)設(shè)的內(nèi)存塊留作備用。本文主要來(lái)和大家聊聊內(nèi)存池的簡(jiǎn)單原理及實(shí)現(xiàn),希望對(duì)大家有所幫助2023-03-03
C語(yǔ)言新手初階教程之三子棋實(shí)現(xiàn)
相信大家在小時(shí)候都用紙和筆與小伙伴們玩過(guò)一個(gè)經(jīng)典的游戲之井字棋,即三子棋,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言新手初階教程之三子棋實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2022-01-01
C++實(shí)現(xiàn)LeetCode(79.詞語(yǔ)搜索)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(79.詞語(yǔ)搜索),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C語(yǔ)言實(shí)現(xiàn)隨機(jī)發(fā)撲克牌
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)隨機(jī)發(fā)撲克牌,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04

