JavaScript中Promise講解和使用方法代碼

Promise 是 JavaScript 異步編程的核心解決方案,它解決了傳統(tǒng)回調(diào)地獄問題,提供了更優(yōu)雅的異步控制流。
面試官:談談你對 Promise 的理解?
回答:
Promise用來解決異步回調(diào)問題,由于 js
是單線程的,很多異步操作都是依靠回調(diào)方法實現(xiàn)的,這種做法在邏輯比較復雜的回調(diào)嵌套中會相當復雜;也叫做回調(diào)地獄;
promise用來將這種繁雜的做法簡化,讓程序更具備可讀性,可維護性;promise
內(nèi)部有三種狀態(tài),pending,fulfilled,rejected;
pending表示程序正在執(zhí)行但未得到結果,即異步操作沒有執(zhí)行完畢,
fulfilled表示程序執(zhí)行完畢,且執(zhí)行成功,
rejected表示執(zhí)行完畢但失??;這里的成功和失敗都是邏輯意義上的;并非是要報錯。其實,promise 和回調(diào)函數(shù)一樣,都是要解決數(shù)據(jù)的傳遞和消息發(fā)送問題,promise 中的 then
一般對應成功后的數(shù)據(jù)處理,catch 一般對應失敗后的數(shù)據(jù)處理。
一、Promise 基礎概念
1.1 什么是 Promise?
Promise 是一個表示異步操作最終完成或失敗的對象,它有三種狀態(tài):
- pending(進行中)
- fulfilled(已成功)
- rejected(已失?。?/li>
1.2 創(chuàng)建 Promise
const promise = new Promise((resolve, reject) => {
// 異步操作
setTimeout(() => {
const success = true;
if (success) {
resolve("操作成功");
} else {
reject("操作失敗");
}
}, 1000);
});
1.3 使用 Promise
promise
.then((result) => {
console.log(result); // "操作成功"
})
.catch((error) => {
console.error(error); // "操作失敗"
});
二、Promise 自帶方法
2.1 靜態(tài)方法
Promise.resolve()
創(chuàng)建一個立即解析的 Promise:
Promise.resolve("立即返回").then(console.log); // "立即返回"
Promise.reject()
創(chuàng)建一個立即拒絕的 Promise:
Promise.reject("錯誤").catch(console.error); // "錯誤"
Promise.all()
Promise.all()方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。等待所有 Promise 完成,或任意一個失敗。
“致命傷”:一個失敗,全盤皆輸
// 假設有三個異步請求:獲取用戶信息、獲取商品列表、獲取消息通知
const fetchUserInfo = fetch("/api/user");
const fetchProducts = fetch("/api/products");
const fetchNotifications = fetch("/api/notifications");
Promise.all([fetchUserInfo, fetchProducts, fetchNotifications])
.then(([userInfo, products, notifications]) => {
// 只有當三個請求都成功時,才會進入這里
renderUserPage(userInfo, products, notifications);
})
.catch((error) => {
// 如果任何一個請求失敗,就會跳到這里
console.error("有一個請求失敗了:", error);
showErrorPage("頁面加載失敗,請重試!");
});
Promise.race()
返回最先完成的 Promise(無論成功或失?。?/p>
const p1 = new Promise((res) => setTimeout(res, 100, "慢"));
const p2 = new Promise((res) => setTimeout(res, 50, "快"));
Promise.race([p1, p2]).then((winner) => {
console.log(winner); // "快"
});
Promise.allSettled()
為了解決 Promise.all 一個失敗,全盤皆輸?shù)倪@個痛點,ES2020 引入了 Promise.allSettled 方法。它的行為更加寬容和穩(wěn)?。?/p>
- 等待所有:它會等待所有輸入的 Promise 都“敲定”(settled),即無論是成功(fulfilled)還是失?。╮ejected)。
- 永不失敗:Promise.allSettled 自身永遠不會被 reject,它總是會成功返回一個數(shù)組。
- 詳情可知:返回的數(shù)組中的每個對象都包含了每個 Promise 的最終狀態(tài)和結果(或原因)。
每個結果對象都有兩種形態(tài):
- 成功:
{ status: 'fulfilled', value: 結果值 } - 失?。?code>{ status: 'rejected', reason: 錯誤原因 }
如何使用 Promise.allSettled:
Promise.allSettled([fetchUserInfo, fetchProducts, fetchNotifications]).then((results) => {
// 注意:這里永遠不會 catch
// results 是一個包含三個對象的數(shù)組
const userInfo = results[0].status === "fulfilled" ? results[0].value : null;
const products = results[1].status === "fulfilled" ? results[1].value : null;
const notifications = results[2].status === "fulfilled" ? results[2].value : null; // 我們可以針對每個結果進行精細化處理
if (userInfo && products) {
// 只要核心數(shù)據(jù)(用戶和商品)還在,就渲染頁面
renderUserPage(userInfo, products, notifications); // notifications 可能是 null
if (!notifications) {
showToast("通知獲取失敗,不影響主要功能");
}
} else {
// 如果核心數(shù)據(jù)缺失,再顯示錯誤頁
showErrorPage("核心數(shù)據(jù)加載失敗");
}
});
// 不需要 .catch,因為它永遠不會被觸發(fā)
使用 Promise.allSettled 優(yōu)勢:
- 體驗提升:即使通知接口掛了,用戶依然能看到頁面主體內(nèi)容,只會收到一個輕量的提示。
- 韌性增強:單個接口的失敗不會導致整個頁面或功能的崩潰。
- 信息完整:我們可以確切地知道每個任務的執(zhí)行結果,并據(jù)此做出更細致的 UI 響應。
Promise.any()
返回第一個成功的 Promise(忽略失敗):
const p1 = Promise.reject("錯誤1");
const p2 = Promise.resolve("成功");
Promise.any([p1, p2]).then((firstSuccess) => {
console.log(firstSuccess); // "成功"
});
2.2 實例方法
.then()
處理 Promise 的成功狀態(tài):
fetch("/api")
.then((response) => response.json())
.then((data) => console.log(data));
.catch()
捕獲 Promise 鏈中的錯誤:
fetch("/api")
.then((response) => response.json())
.catch((error) => console.error("請求失敗:", error));
.finally()
無論成功或失敗都會執(zhí)行:
fetch("/api")
.then((response) => response.json())
.finally(() => console.log("請求結束"));
三、Promise 高級技巧
3.1 鏈式調(diào)用
function getUser(id) {
return fetch(`/users/${id}`)
.then((response) => response.json())
.then((user) => fetch(`/profile/${user.profileId}`))
.then((response) => response.json());
}
3.2 錯誤處理策略
// 方式1:每個 then 后單獨 catch
fetch("/api")
.then((res) => res.json())
.catch(handleJSONError)
.then((data) => process(data))
.catch(handleProcessError);
// 方式2:全局 catch
fetch("/api")
.then((res) => res.json())
.then((data) => process(data))
.catch(handleAnyError);
3.3 取消 Promise
原生 Promise 無法取消,但可以通過封裝實現(xiàn):
function cancellablePromise(promise) {
let isCancelled = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then((value) => !isCancelled && resolve(value)).catch((error) => !isCancelled && reject(error));
});
return {
promise: wrappedPromise,
cancel: () => {
isCancelled = true;
}
};
}
3.4 Promise 化回調(diào)函數(shù)
將回調(diào)風格的函數(shù)轉(zhuǎn)換為 Promise:
const fs = require("fs");
function readFilePromise(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
四、Promise 與 async/await
4.1 基本轉(zhuǎn)換
// Promise 風格
function getData() {
return fetch("/api").then((res) => res.json());
}
// async/await 風格
async function getData() {
const res = await fetch("/api");
return res.json();
}
4.2 錯誤處理對比
// Promise
fetch("/api")
.then((res) => res.json())
.catch(console.error);
// async/await
try {
const res = await fetch("/api");
const data = await res.json();
} catch (err) {
console.error(err);
}
五、常見問題與解決方案
5.1 Promise 內(nèi)存泄漏
未處理的 Promise 拒絕會導致內(nèi)存泄漏:
// 錯誤示范(未捕獲的拒絕)
function riskyOperation() {
return new Promise((_, reject) => {
setTimeout(reject, 1000, "錯誤");
});
}
// 正確做法
riskyOperation().catch(() => {});
5.2 并行與順序執(zhí)行
// 順序執(zhí)行
async function sequential() {
await task1();
await task2(); // 等待 task1 完成
}
// 并行執(zhí)行
async function parallel() {
await Promise.all([task1(), task2()]);
}
六、總結
Promise 的核心優(yōu)勢:
- 鏈式調(diào)用:解決回調(diào)地獄
- 統(tǒng)一錯誤處理:通過
.catch()集中管理 - 組合能力強:
Promise.all/race等實現(xiàn)復雜控制流
最佳實踐建議:
- 始終返回 Promise 鏈(避免中斷)
- 使用
async/await提升可讀性 - 不要忘記錯誤處理
// 終極實踐示例
async function getFullData() {
try {
const [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);
return { user, posts };
} catch (error) {
console.error("加載失敗:", error);
throw error; // 向上傳遞
}
}
常用方法的區(qū)別
| 方法 | 核心邏輯 | 成功條件 | 失敗條件 | 典型使用場景 |
|---|---|---|---|---|
Promise.all(iterable) | “全部成功” 等待所有 Promise 完成 | 所有 Promise 都成功 (fulfilled) | 有任意一個 Promise 失敗 (rejected) | 并行處理多個相互依賴的任務,如:同時上傳多張圖片、同時獲取多個 API 數(shù)據(jù)以渲染頁面。 |
Promise.race(iterable) | “競賽” 取最先完成(無論成敗)的 Promise 結果 | 最先完成的 Promise 是成功 (fulfilled) | 最先完成的 Promise 是失敗 (rejected) | 1. 設置超時/競速:為異步操作添加超時限制。 2. 從多個最快響應的來源(如 CDN)獲取資源。 |
Promise.allSettled(iterable) | “無論成敗” 等待所有 Promise 最終敲定 (settled) | 總是成功 (返回每個 Promise 的最終狀態(tài)和結果數(shù)組) | 不會失敗 | 當需要知道每個異步操作的最終結果時,如:批量提交表單,無論單個成功或失敗都需要記錄日志或進行下一步處理。 |
Promise.any(iterable) | “任一成功” 取最先成功的 Promise 結果 | 有任意一個 Promise 成功 (fulfilled) | 所有 Promise 都失敗 (rejected) | 1. 尋找最快可用資源:從多個鏡像服務器下載同一個文件,使用最先響應的。 2. 提供備用方案,只要一個成功即可。 |
快速選擇指南
當你面對多個異步操作時,可以這樣選擇:
- 需要所有操作都成功才能繼續(xù) →
Promise.all() - 只需第一個完成的操作結果(無論成?。?→
Promise.race() - 需要知道每個操作的最終結果(無論成敗) →
Promise.allSettled() - 只需第一個成功的操作結果 →
Promise.any()
總結
到此這篇關于JavaScript中Promise講解和使用方法的文章就介紹到這了,更多相關js Promise使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaScript獲取客戶端計算機硬件及系統(tǒng)等信息的方法
本文為大家詳細介紹下如何使用JavaScript獲取客戶端計算機硬件及系統(tǒng)等信息,下面有個不錯的示例,感興趣的朋友可以參考下2014-01-01
JavaScript使用Promise實現(xiàn)并發(fā)請求數(shù)限制
本文主要介紹了JavaScript使用Promise實現(xiàn)并發(fā)請求數(shù)限制,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-04-04

