現代 Web 開發嚴重依賴非同步活動來實現響應式、互動式應用程式。無論是從 API 檢索資料、讀取檔案或運行計時器,這些進程都必須在背景運行,而不會凍結介面。 JavaScript 為您提供了一種可靠的方式來處理這些工作。本文涵蓋了您需要了解的有關 Promise 的所有信息,包括基本思想和高級功能,以開發無錯誤的非同步程式。
在本文中您將了解 —
什麼是 Promise?
為什麼要用 Promise?
Promise 如何運作?
處理 Promise
連鎖承諾
Promise 中的錯誤處理
進階 Promise 功能
有 Promise 的 JavaScript 執行流程(重要)
將 Promise 鏈轉換為非同步/等待
最佳實務與常見錯誤
JavaScript 中的 Promise 相當於做出「承諾」在未來做某事。當你做出承諾時,你就是在說:「我保證稍後會給你結果。」這個結果可能是成功,也可能是失敗。
換句話說,Promise 是一個反映非同步操作最終成功(或失敗)及其結果值的物件。它允許您將處理程序與非同步操作的成功或失敗關聯起來,使您的程式碼更易於閱讀和維護。
例如,在 JavaScript 中,耗時的操作(例如從伺服器檢索資料)通常是透過回調完成的。回調只是一個傳遞給另一個函數以在任務完成後執行的函數。例如,您可以使用回調來處理來自伺服器的資料。
但是,當有複雜的操作時,回呼的使用就變得相當混亂。這種混亂被稱為“回調地獄”,其中一個可以在另一個中進行回調,這使得程式碼不可讀且難以管理。
回調地獄範例:
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
如上所示,由於其深層嵌套結構(通常稱為“回調地獄”),此類程式碼在較大的程式碼庫中變得越來越難以閱讀和維護。
引入 Promise 來解決這個問題,透過允許以更易讀的方式進行鏈接,提供一種更乾淨、更有組織的方式來處理非同步任務。
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
這種方法扁平化了結構,使程式碼更具可讀性和可維護性。
JavaScript 中的 Promise 可以處於以下三種狀態之一:
待處理:這是第一步。承諾還沒兌現。
Fulfilled:Promise 已成功完成,這意味著它已解決並且具有價值。
已拒絕:Promise 未成功完成,並且帶有錯誤訊息。
基本文法
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
在此範例中,promise 在 1 秒後解析,並顯示訊息「Promise returned!」。 .then() 方法用於處理解析後的值。
.then()方法用於處理promise成功完成時發生的情況。它註冊函數(回調)以在承諾完成時運行。
const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve("Promise resolved!"); }, 1000); }); myPromise.then(result => console.log(result));
.catch()方法用於處理promise失敗時發生的情況。它註冊一個函數(回調)以在 Promise 被拒絕時運行。
myPromise.then(data => { console.log("Data received:", data); });
.finally() 方法可以讓你在 Promise 完成後執行一些程式碼,無論成功與否。
myPromise.catch(error => { console.error("Error:", error); });
連結可讓您透過傳遞前一個任務的結果來順序執行任務。然後繼續進行next.then()。這允許您按順序處理多個非同步任務。
連結範例:
myPromise.finally(() => { console.log("Cleanup tasks"); });
此範例使用each.then()來處理流程中的每個步驟,從而實現清晰的資料流。這可以讓您看到一個階段的結果如何轉移到下一階段。
Promise 透過讓它們將鏈向下傳遞給 .catch() 方法來解決,從而簡化了錯誤處理。這消除了在每個階段處理失敗的需要,使您的程式碼更清晰且更易於管理。
錯誤傳播範例:
fetch('https://api.example.com/user') .then(response => response.json()) .then(data => { console.log("Processed data:", data); return processData(data); }) .then(finalResult => { console.log("Final result:", finalResult); }) .catch(error => console.error("Error:", error));
如果 Promise 鏈中的任何一步失敗,錯誤將被 .catch() 區塊捕獲。這使得您可以輕鬆處理問題並保持程式碼順利運行。
Promise.all() 方法可讓您同時執行多個 Promise 並等待它們全部完成。如果所有承諾都得到履行,您將收到每項承諾的結果。如果任何承諾失敗,它會偵測到錯誤。
fetchData() .then(processData) .then(saveData) .catch(error => console.error("An error occurred:", error));
在此範例中,如果任何 Promise 失敗,則整個 Promise.all() 都會失敗。
Promise.race() 方法傳回第一個完成的 Promise 的結果,無論成功或失敗。
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
在此範例中,無論哪個 Promise(fetchData1 或 fetchData2)先完成,其結果都會記錄到控制台。
Promise.allSettled()方法等待你給它的所有promise都處於成功或失敗狀態,然後完成。然後傳回一個數組,其中包含每個承諾的結果。
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
在此範例中,Promise.allSettled() 等待 fetchData1() 和 fetchData2() 完成。然後它記錄每個承諾的狀態和結果(或錯誤)。這樣,您就可以看到每個 Promise 發生了什麼,無論它們是成功還是失敗。
Promise.any() 方法等待 Promise 清單中的第一個 Promise 被正確解析。如果至少有一個 Promise 解決,則 Promise.any() 方法將傳回該值。如果所有的 Promise 都被拒絕,這個方法將會拋出一個錯誤。
const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve("Promise resolved!"); }, 1000); }); myPromise.then(result => console.log(result));
在此範例中,Promise.any() 等待第一個 Promise 成功解析。過程傳回第一個成功的 Promise 的結果,在本例中,promise2 的值為「Success A」。如果所有承諾都被拒絕,則執行 .catch() 區塊,並記錄錯誤訊息。當您想要收到第一個成功的 Promise 的結果而不必等待其餘的結果時,此策略非常有用。
這裡有一個例子來說明這一點:
myPromise.then(data => { console.log("Data received:", data); });
在此範例中:
console.log(2) 首先運行,因為它是常規同步操作。
console.log (6) 接下來運行,因為它也是同步的。
promise 的.then() 在 setTimeout 回調之前運行,因為 Promise 是微任務,具有更高的優先權,因此打印 3.
最後,setTimeout 回調運行,因為它是一個巨集任務並列印 4。
所以永遠記住,由於微任務佇列的優先權,promise's.then() 在 setTimeout 回調之前執行。
在 JavaScript 中,程式碼以特定順序執行:首先是同步程式碼,然後是微任務(如 Promise),最後是巨集任務(如 setTimeout)。
這裡有一個例子來解釋這一點:
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
在此範例中,同步程式碼首先運行,記錄 3、6、2、7 和 8。同步程式碼完成後,將處理微任務(then() 回呼),記錄 1 和 9。最後,巨集任務(來自 setTimeout)依延遲順序執行,記錄 21 (0ms) 和 13 (10ms)。這突顯了 JavaScript 的執行順序:同步程式碼 >微任務>巨集任務。
當您建立承諾時,第一個解決或拒絕的呼叫是唯一重要的。所有其他呼叫均被駁回。
這裡有一個例子來說明這一點:
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
在此範例中,promise 使用值 1 進行解析。第二個解析和拒絕呼叫將被忽略,因為 Promise 已透過第一個解析進行結算。
當你連結 Promise 時,each.then() 會處理流程中的一個步驟。
const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve("Promise resolved!"); }, 1000); }); myPromise.then(result => console.log(result));
在此範例中,Promise.resolve(1) 以值 1 開頭,但第一個 .then(() => 2) 傳回 2。下一個 .then(3) 被忽略,並且值 2 被傳遞。 .then((value) => value * 3) 將值乘以 3,結果是 6。 .then(Promise.resolve(4)) 不會改變值,最後,.then(console. log)logs 6。這演示了值如何透過鏈傳遞,非函數值被忽略。
myPromise.then(data => { console.log("Data received:", data); });
在此範例中,我們將多個 .then()、.catch() 和 .finally() 方法連結在一起,以展示如何處理 Promise 解析的不同階段。讓我們來分解一下:
finally() 沒有收到參數:
finally() 區塊執行清理程式碼,但不接受或傳遞任何值。它用於確保某些程式碼運行,無論承諾的結果如何。
在finally()中回傳一個值不會影響promise:
如果您在finally()區塊中傳回一個值,它不會影響promise鍊或最終值。它在承諾解決/拒絕後執行,但不會修改結果。
在finally()中拋出錯誤會導致拒絕:
如果你在finally()中拋出錯誤或回傳被拒絕的promise,將會導致promise鏈被拒絕,並帶有錯誤或拒絕原因。
myPromise.catch(error => { console.error("Error:", error); });
或
myPromise.finally(() => { console.log("Cleanup tasks"); });
範例:
fetchData((data) => { processData(data, (processedData) => { saveData(processedData, (result) => { console.log(result); }); }); });
Async/await 是一種使用 Promise 的方法,使程式碼更像以同步模式編寫的程式碼。經常使用的術語是“語法糖”,因為它提供了更直接、更清晰的非同步程式碼執行路徑。
fetchData() .then(processData) .then(saveData) .then(console.log) .catch(console.error);
您可以使用 Promise.all() 將 Promise 與 async/await 結合以實現並行執行。
const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve("Promise resolved!"); }, 1000); }); myPromise.then(result => console.log(result));
避免深層巢狀:使用連結或非同步/等待來保持程式碼平坦和可讀。
總是處理錯誤: 確保每個 Promise 鏈都有 a.catch() 或 try/catch 區塊。
明智地使用並行執行:僅當任務獨立但需要一起完成時才使用 Promise.all()。
JavaScript Promise 是處理耗時操作(例如在伺服器上檢索資料)的最佳方法之一。它們甚至可以幫助您編寫更清晰、更易於維護的程式碼,而您所學的實踐將使您能夠充分利用非同步編碼。一旦你獲得了一些實務經驗並開始優雅地處理錯誤,Promise 將成為 JavaScript 的重要組成部分。
感謝您的閱讀!如果您覺得這篇文章有幫助,請隨時突出顯示、鼓掌、發表評論,甚至在 Twitter/X 和 LinkedIn 上與我聯繫,因為我非常感激並幫助保持此類內容免費!
以上是關於 JavaScript Promise 及其工作原理,您需要了解的一切的詳細內容。更多資訊請關注PHP中文網其他相關文章!