繼上篇提及到回呼函式(Callback Function),今天來講 Promise 與 async/await!
Promise 是 JavaScript 中用於處理非同步操作的一種概念。
主要目的是更好地處理非同步操作的 Callback Hell (回調地獄)問題,使代碼更具可讀性和可維護性。
處理非同步操作:
Promise 是處理非同步操作的標準方式,例如發送網絡請求、讀取文件、操作數據庫等。
使得代碼可以在非同步操作完成之後執行相應的操作,而不需要等待。
解決回調地獄問題:
當多個非同步操作依賴於彼此時,使用回調函式可能導致代碼結構深度嵌套,
稱為回調地獄(Callback Hell)。
Promise 可以幫助簡化和清晰化這種情況下的代碼。
序列化非同步操作:
有時需要按特定順序執行一系非同步操作,並且每個操作可能依賴於前一個操作的結果。
Promise 允許你使用 .then()
方法將這些操作鏈接在一起,確保它們按順序執行。
處理錯誤:
Promise 具有 .catch()
方法,可以用於捕獲和處理非同步操作中的錯誤,提供更好的錯誤處理機制。
.then()
:用於處理操作成功的情況,接受一個回呼函式。.catch()
:用於處理操作失敗的情況,接受一個回呼函式。.finally()
:無論操作成功還是失敗,都會執行的回呼函式。.then()
和 .catch()
使用情境想像你正在訂外賣,並希望知道當外賣送達時要做些什麼。
function orderFood() {
console.log("開始訂外賣...");
const deliveryTime = Math.random() * 10000; // 模擬外賣送達時間(0 到 10 秒)
// 使用 Promise 模擬外賣送達
const deliveryPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.2; // 模擬外賣送達成功或失敗
if (success) {
resolve("外賣已送達!");
} else {
reject("對不起,配送出了問題。");
}
}, deliveryTime);
});
// 使用 .then() 處理外賣送達成功情況
deliveryPromise.then(successMessage => {
console.log(successMessage);
console.log("確保你有筷子、餐盤和餐巾紙。");
});
// 使用 .catch() 處理外賣送達失敗情況
deliveryPromise.catch(errorMessage => {
console.error(errorMessage);
console.log("不要擔心,你可以聯繫外賣店解決問題。");
});
console.log("訂單已下單,等待外賣送達...");
}
// 訂外賣
orderFood();
我們使用 .then()
方法處理成功情況,當外賣成功送達時,我們顯示成功消息並給予一些提示。
當外賣送達失敗時,我們使用 .catch()
方法處理錯誤情況,並提供相應的錯誤消息和建議。
.finally()
使用情境讓我們通過一個簡單的實際例子來看看 .finally()
的使用情境。
假設你正在開發一個文件上傳功能,用戶可以上傳文件到服務器。
在每次文件上傳之前,你希望顯示一個加載器,無論上傳成功還是失敗,都需要隱藏該加載器。
這時,可以使用 .finally()
來確保不論上傳的結果如何,都會隱藏加載器。
function uploadFile(file) {
const uploadIndicator = document.getElementById("upload-indicator");
showLoadingIndicator(uploadIndicator);
return new Promise((resolve, reject) => {
// 模擬文件上傳,這裡使用setTimeout模擬非同步操作
setTimeout(() => {
const success = Math.random() > 0.5; // 模擬成功或失敗
if (success) {
resolve("文件上傳成功");
} else {
reject("文件上傳失敗");
}
}, 2000);
})
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
})
.finally(() => {
hideLoadingIndicator(uploadIndicator);
});
}
function showLoadingIndicator(indicator) {
// 顯示加載器
indicator.style.display = "block";
}
function hideLoadingIndicator(indicator) {
// 隱藏加載器
indicator.style.display = "none";
}
const fileInput = document.getElementById("file-input");
fileInput.addEventListener("change", event => {
const file = event.target.files[0];
if (file) {
uploadFile(file);
}
});
當用戶選擇文件並觸發上傳操作時,我們首先顯示了一個加載器,然後使用 Promise 來模擬文件上傳操作。不論上傳成功還是失敗,.finally()
中的代碼都會確保隱藏加載指示器,從而提供更好的用戶體驗。
async/await
是 JavaScript 中用於處理非同步操作的一種語法糖,
基於 Promise 提供了更好的非同步操作處理方式,使代碼更易讀且更容易理解。
async 函式:
使用 async
關鍵字來定義非同步函式,這些函式返回一個 Promise 對象,可以處理非同步操作。
await 關鍵字:await
用於等待一個 Promise 完成。當在 async 函式中使用 await 時,該函式會暫停執行,直到等待的 Promise 完成並返回結果。這使得代碼看起來更像同步代碼,因此可以更容易地理解和維護。
錯誤處理:
使用 try...catch 構造來捕獲非同步操作中的錯誤,就像處理同步代碼一樣。
多個非同步操作的處理:
async/await 可以用於處理多個非同步操作,例如按順序執行多個非同步任務,或並行執行它們,從而使代碼的流程更容易管理。
我們可以使用剛剛外賣訂購的例子來進一步說明 async/await
的用法。
假設你要訂外賣,然後等待外賣送達,然後再享用外賣。
// 模擬外賣送達的函式,返回 Promise
function deliverFood() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.2; // 模擬成功或失敗
if (success) {
resolve("外賣已送達!");
} else {
reject("對不起,配送出了問題。");
}
}, 2000); // 模擬兩秒的送達時間
});
}
// 定義一個 async 函式,訂外賣並等待送達
async function orderAndAwaitDelivery() {
try {
console.log("開始訂外賣...");
const deliveryResult = await deliverFood();
console.log(deliveryResult);
console.log("確保你有筷子、餐盤和餐巾紙。");
} catch (error) {
console.error("配送出現問題:", error);
}
}
// 執行 async 函式
orderAndAwaitDelivery();
deliverFood
函式模擬外賣送達,並返回一個 Promise。orderAndAwaitDelivery
是一個 async 函式,內部使用 await
等待外賣送達的完成。
當我們執行 orderAndAwaitDelivery
函式時,它首先輸出 "開始訂外賣...",然後等待外賣送達,最後根據送達的結果輸出相應的消息。如果送達過程中出現問題,則捕獲並處理錯誤。
希望這些關於 Promise 和 async/await 的解釋能讓大家更好理解和應用這兩個重要的非同步操作概念。
在現代 JavaScript 開發中非常常見,用於處理各種非同步任務,提高代碼的效能和可讀性。
下篇想來談談 Event Loop (瀏覽器中的事件循環)!
文章同步於個人部落格:Viiisit!(歡迎參觀 ୧ʕ•̀ᴥ•́ʔ୨)