初學者指南:了解 JavaScript 中的 Promise 和 await
更新日期: 2024 年 9 月 14 日
在學習 JavaScript 處理非同步操作時,你可能會遇到兩個重要的概念:Promise 和 async/await。這篇文章將帶你深入了解這些概念,並展示如何在你的代碼中使用它們。
什麼是 Promise?
Promise 是用來處理非同步操作的一種 JavaScript 物件。它代表了一個尚未完成,但最終會完成(或失敗)的操作。
Promise 的三種狀態
- Pending(待定):初始狀態,操作尚未完成或失敗。
- Fulfilled(已完成):操作成功完成。
- Rejected(已拒絕):操作失敗。
如何創建和使用 Promise
你可以通過 new Promise 來創建一個 Promise,並使用 .then 和 .catch 方法來處理它的結果:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true; // 模擬操作成功或失敗
if (success) {
resolve("操作成功!");
} else {
reject("操作失敗!");
}
}, 2000);
});
myPromise
.then((message) => {
console.log(message); // 打印 "操作成功!"
})
.catch((error) => {
console.error(error); // 打印 "操作失敗!"
});
若看不懂以上內容,請先閱讀此文:初學者指南:了解 JavaScript 的 Promise 物件
什麼是 async/await?
async/await 是在 ECMAScript 2017(ES8)中引入的語法糖,用於更方便地處理 Promise。
它使得非同步代碼看起來像同步代碼,從而提高了代碼的可讀性。
使用 async 定義非同步函數
async 關鍵字用來定義一個非同步函數。非同步函數總是返回一個 Promise:
async function myAsyncFunction() {
return "Hello, async!";
}
myAsyncFunction().then((message) => {
console.log(message); // 打印 "Hello, async!"
});
使用 await 等待 Promise
await 關鍵字用來等待一個 Promise 的結果。
它只能在 async 函數內使用:
async function myAsyncFunction() {
const message = await myPromise; // 等待 myPromise 完成
console.log(message); // 打印 "操作成功!"
}
myAsyncFunction();
這段代碼的作用與使用 .then
方法相同,但看起來更像同步代碼。
.then 方法與 async/await 差異
讓我們來對比一下使用 .then
方法和使用 async/await
的代碼,從而更好地理解這一點。
使用 .then 方法的代碼
首先,我們看看如何使用 .then 方法來處理 Promise:
// 定義一個模擬非同步操作的函數
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true; // 模擬操作成功或失敗
if (success) {
resolve("數據獲取成功!");
} else {
reject("數據獲取失敗!");
}
}, 2000);
});
}
// 使用 .then 和 .catch 方法來處理 Promise
fetchData()
.then((data) => {
console.log(data); // 打印 "數據獲取成功!"
return data; // 可以選擇返回一些數據,繼續鏈式調用
})
.catch((error) => {
console.error(error); // 打印 "數據獲取失敗!"
});
使用 async/await 的代碼
接下來,我們看看如何使用 async/await 來處理同樣的 Promise:
// 定義一個模擬非同步操作的函數
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true; // 模擬操作成功或失敗
if (success) {
resolve("數據獲取成功!");
} else {
reject("數據獲取失敗!");
}
}, 2000);
});
}
// 使用 async/await 來處理 Promise
async function getData() {
try {
const data = await fetchData(); // 等待 fetchData 完成
console.log(data); // 打印 "數據獲取成功!"
} catch (error) {
console.error(error); // 打印 "數據獲取失敗!"
}
}
getData();
對比分析
- 結構化:
- .then 方法:使用 .then 方法會導致鏈式調用,當有多個非同步操作需要依次進行時,會產生多層嵌套。
- async/await:使用 async/await 則使得代碼結構更像同步操作,線性化的代碼結構更直觀。
- 錯誤處理:
- .then 方法:錯誤處理需要在鏈的末端使用 .catch 方法,或者在每個 .then 內部進行處理。
- async/await:使用 try/catch 块來處理錯誤,錯誤處理邏輯更加集中,代碼更易讀。
- 可讀性:
- .then 方法:當有多個 .then 需要處理時,代碼會變得不太好閱讀。
- async/await:代碼更加簡潔,易於理解和維護。
更複雜的示例
假設我們有多個非同步操作需要依次進行,這是使用 .then
方法和 async/await
的對比:
使用 .then 方法:
function firstTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("完成任務1");
}, 1000);
});
}
function secondTask() {
return new Promise((resolve,
reject) => {
setTimeout(() => {
resolve("完成任務2");
}, 1000);
});
}
function thirdTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("完成任務3");
}, 1000);
});
}
firstTask()
.then((message) => {
console.log(message); // 打印 "完成任務1"
return secondTask();
})
.then((message) => {
console.log(message); // 打印 "完成任務2"
return thirdTask();
})
.then((message) => {
console.log(message); // 打印 "完成任務3"
})
.catch((error) => {
console.error(error);
});
使用 async/await
:
function firstTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("完成任務1");
}, 1000);
});
}
function secondTask() {
return new Promise((resolve,
reject) => {
setTimeout(() => {
resolve("完成任務2");
}, 1000);
});
}
function thirdTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("完成任務3");
}, 1000);
});
}
async function runTasks() {
try {
const firstMessage = await firstTask();
console.log(firstMessage); // 打印 "完成任務1"
const secondMessage = await secondTask();
console.log(secondMessage); // 打印 "完成任務2"
const thirdMessage = await thirdTask();
console.log(thirdMessage); // 打印 "完成任務3"
} catch (error) {
console.error(error);
}
}
runTasks();
結語
使用 async/await 可以讓你寫出更具可讀性和可維護性的代碼,特別是在處理多個非同步操作時。
希望這篇文章能幫助你更好地理解 async/await 與 .then 方法之間的對比,並能夠有效地在你的 JavaScript 項目中使用它們。