在 JavaScript 中等待 Promise 得到解決
在 ECMA Script (ES6) 版本中,引入了 JavaScript 程式語言的大部分現代特性。該語言的特性是 JavaScript 最突出和最廣泛使用的特性之一,稱為 Promise,在這個版本中也被引入。
眾所周知,JavaScript 語言是一種單執行緒語言,這意味著只能按特定順序執行一項任務。在某些情況下,這可能會產生問題。
例如,如果你使用了 setTimeout()
函式,在三秒後執行,JavaScript 編譯器將不會等待 3 秒。如下所示,它將開始執行下一部分程式碼。
function abc(){
console.log("a");
setTimeout(()=>{
console.log("b");
},3000)
console.log("c");
}
abc();
輸出:
a
c
b
這裡,b
必須在 c
之前列印,但事實並非如此。因此,為了克服這個問題,在 JavaScript 中引入了 Promise,它可以幫助我們執行非同步任務。
讓我們看看 Promise 是如何工作的,並等到 Promise 在後臺解決。此外,我們將在本文中學習的大部分概念都受 JavaScript ES6 及更高版本的支援,並且可能不適用於 IE 等較舊的瀏覽器。
JavaScript 中的 Promise 是什麼
每當我們執行任何請求(如資料庫請求或 API 請求)時,可能需要一段時間才能從伺服器獲取資料。我們不能說這樣的操作在同時執行許多請求的生產環境中需要多少時間。
JavaScript 中的 Promise 允許我們等待此類操作或任務完成執行,並根據任務是否完成,我們可以採取進一步的行動。
我們必須使用 new
關鍵字建立一個 Promise
類物件才能使用 Promise。Promise 有兩個引數,resolve 和 reject。
resolve()
方法返回一個用值解析的承諾物件。如果在執行 Promise 時發生錯誤,則拒絕方法將返回錯誤。
Promise 使用 async
和 await
關鍵字。這些關鍵字在實現 Promise 時是重要且必要的。
我們將在本文後面詳細瞭解它們。
JavaScript 中的 Promise 階段
與 Promises 的類比可以是,假設你和你的朋友互相承諾,你們將在星期天一起去看電影。並假設它的星期五和承諾是今天作出的。
由於週日還沒有到來,我們可以從技術上說 Promise 正在等待中。如果你在星期天遇到你的朋友,承諾就實現了,如果你因為不去看電影而違反承諾,那麼承諾就會被拒絕。
JavaScript 中的 Promise 分 3 個階段執行,它們如下所示。
- Pending:當一個 promise 被執行時,它被稱為處於 pending 階段。
- Fulfilled:當一個 promise 成功完成它的執行時,它被解析並返回執行的操作的值。這就是 Promise 處於實現階段的地方。
- Rejected:如果 Promise 在執行過程中失敗,它會被拒絕並返回錯誤訊息。這就是 Promise 處於被拒絕階段的地方。
在 JavaScript 中使用 async
和 await
關鍵字實現 Promise
async
和 await
關鍵字在實現 Promise 時齊頭並進。
async
關鍵字可以與你認為需要時間執行的函式一起使用。這使得它們的功能是非同步的。
這個關鍵字告訴 JavaScript 引擎該函式中的某些部分程式碼可能需要一些時間才能執行,你需要等到它完成執行。
我們必須指定該函式中的哪一部分程式碼可能需要一些時間來執行。這是我們使用 await
關鍵字的地方。
因此,無論你在該函式中使用什麼 await
關鍵字,JavaScript 引擎都會等待該部分完全執行。如果執行成功,則返回已完成的 Promise,否則 Promise 將被拒絕。
下面的示例說明了這一點。
在這裡,我們有一個名為 myPromise
的函式。我們在這個函式中建立了一個 Promise
,要麼已解決,要麼已被拒絕。
此函式的工作是從 API 獲取 JSON 資料。由於我們從 API 請求資料,Promise
可能需要一些時間來執行,所以我們使用 await
來等待 Promise 解決。
當我們在返回一個 Promise
之前使用 await
時,我們必須將 myPromise
函式設定為 async
。
我們使用的 API 是來自 JSONPlaceholder 網站的免費 API。使用此 API,我們將獲取帖子資料。
我們可以使用 fetch()
函式從這個 API 中獲取資料。在此函式獲取資料後,我們必須使用 then()
函式指定下一步要做什麼。
我們只需將來自 fetch()
函式的資料作為引數返回給 then()
函式。引數的名稱可以是任何名稱,我們將 response
作為引數名稱。
最後,我們將通過使用 response.json()
函式將結果轉換為 JSON 格式來返回 Promise 的解析。
async function myPromise(){
return await new Promise((resolve, reject)=>{
fetch("https://jsonplaceholder.typicode.com/posts").then(response => {
resolve(response.json());
}).catch(error =>{
reject(error);
});
})
}
如果我們在從 API 獲取資料時遇到一些錯誤,那將由 catch()
函式處理。該函式將在 reject()
函式的幫助下返回錯誤。
在 Promise 被解決後,你可以對資料做任何你想做的事情,它在 then()
函式的幫助下返回。你可以有多個 then()
函式,它們將按順序一個接一個地執行。
如果你想捕捉錯誤,你可以使用 catch()
函式。
myPromise().then(result =>{
result.forEach(element => {
var heading = document.createElement('h2');
heading.innerHTML = element.title;
document.body.appendChild(heading);
});
});
輸出:
在 myPromise()
函式返回一個已解決的承諾後,我們使用 then()
函式獲取帖子的標題並將其顯示在 HTML 文件中。
在這裡,我們建立了一個 h2
標題標籤,並將我們從帖子 API 收到的結果資料中的標題附加到 HTML 文件的 body
中。
Sahil is a full-stack developer who loves to build software. He likes to share his knowledge by writing technical articles and helping clients by working with them as freelance software engineer and technical writer on Upwork.
LinkedIn