Promises in JavaScript(譯)
現實生活中的承諾只是對“一些事情”的保證。因此,當有人向您承諾時會發生什麼? 他們為您提供保證,您可以以此為基礎進行提規劃。 現在,諾言可以兌現也可以違背。 因此,當您信守諾言時,您會期望從諾言中得到一些東西。 您可以將promise的輸出用於您的進一步操作或計劃。 但是,當承諾違背時,您想知道為什麼做出承諾的人不能跟上交易,而是會採取相應的下一個行動。JavaScript也提供了一種類似的“承諾”概念來處理非同步呼叫。 本文涵蓋以下主題,讓我們瞭解“ JavaScript中的Promises”的詳細資訊:
- JavaScript中的Promises是什麼?
- 何時在JavaScript中使用Promises?
- Promises如何在JavaScript中工作?
- 在JavaScript中建立Promise的過程。
- 如何在JavaScript中使用Promise?
- 如何使用.then()函式?
- 如何使用.catch()函式?
- 如何使用.finally()函式?
- 如何將Promise.all()函式?
- 如何使用Promise.race()函式?
JavaScript中的Promises是什麼?
JavaScript中的Promise是持有非同步操作未來值的物件。 例如,如果我們要從伺服器請求一些資料,則promise承諾我們將獲得將來可以使用的資料。
一個promise物件擁有如下狀態:
- Pending:這是初始狀態,結果尚未準備好,正在等待非同步操作完成。
- Resolved/Fulfilled:表示執行的操作已成功完成。 即,函式返回了承諾值。
- Rejected:表示執行的操作失敗或發生錯誤。 即函式未返回承諾值。
現在,讓我們理解下在JavaScript中需要promise做些什麼,因為通過回撥它本身來處理非同步操作。
何時在JavaScript中使用Promises?
正如我們在JavaScript中的回撥文章中所討論的那樣,回撥函式用於處理非同步執行。 回撥函式指示非同步操作完成後JavaScript應該執行的操作。
這是執行中的回撥函式的最簡單示例:
<html> <body> Demonstrating callback in javascript:</br> <script type="text/javascript"> function i_take_1_sec() { return setTimeout(() => { document.write('I was no: 2 and I take 1 second</br>') }, 1000); } function i_take_10_sec(callback) { return setTimeout(() => { document.write('I was no: 1 and I take 10 seconds</br>') callback() }, 10000); } function run (){ i_take_10_sec(i_take_1_sec); } run(); </script> </body> </html>
儲存名稱為callbackOne.html的檔案,然後在任何瀏覽器(Chrome,Firefox或IE)中開啟它。 它應該將輸出顯示為:
Promises如何在JavaScript中工作?
為了理解promise到底是如何工作的,讓我們舉個例子:考慮到您正在向母親作出諾言,說您將在一天之後收拾完房間。 因此,可能發生兩種可能的情況,要麼您要打掃房間,要麼不打掃房間並違背諾言。 讓我們用JavaScript來寫那個承諾。
let promiseCleanRoom = new Promise(function(resolve,reject){
cleanRoom = true;
if(cleanRoom){
resolve('Cleaned the Room');
}else{
reject('Broke the promise');
}
});
上面的程式碼塊顯示瞭如何建立承諾。 即,當執行此承諾時,它將基於cleanRoom值給出解決狀態或拒絕狀態。
我們可以將以上建立的promise稱為或使用:
promiseCleanRoom.then((result)=>{
console.log(result)
})
在上面的程式碼片段中,它顯示瞭如何使用已建立的承諾,並且有“ .then”方法,該方法僅在滿足或解決給定的承諾時才會執行某些操作。 在這種情況下,它將在解決時打印出諾言傳送的結果,即"Cleaned the Room"
如果承諾被破壞或在這種情況下發生了一些錯誤,還會發生另外一種情況。 然後,我們可以使用“ .catch”塊,該塊將允許處理損壞的或錯誤的例項。
promiseCleanRoom.then((result)=>{
console.log(result)
}).catch((result)=>{
console.log(result) //will execute if promise is rejected or errored out
})
假設,如果諾言被破壞,那麼它將通過跳過then塊來執行catch塊,並且輸出將是“Broke the promise”。
注意:我們將在以下各節中詳細介紹“ .then”和“ .catch”方法。
在JavaScript中如何建立一個Promise?
如上所述,JavaScript中的Promise是一個物件,代表非同步操作的最終完成或失敗。 其語法如下所示:
語法:
const promise = new Promise(function(resolve,reject){
//do something
});
注意:我們使用Promise建構函式建立一個新的Promise,該建構函式使用一個引數,一個回撥函式(也稱為executor函式),該函式依次使用兩個回撥函式,resolve和reject。
promise建立後,executor函式立即執行。 promise通過呼叫resolve()方法進行解析,並通過呼叫reject()方法被拒絕。
在以下程式碼段的幫助下,讓我們嘗試瞭解Promise在JavaScript中的用法和工作方式。 在這裡,我們將使用promise物件修改回撥地獄程式(在回撥文章中有所介紹)。
<html>
<body> Demonstrating promise in javascript:</br>
<script type="text/javascript">
function i_take_10_sec()
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 1 and I take 10 seconds');
}, 10000);
})
}
function i_take_1_sec()
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 2 and I take 1 second');
}, 1000);
})
}
function i_take_5_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 3 and I take 5 second')
}, 5000);
})
}
function i_take_7_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 4 and I take 7 second')
}, 7000);
})
}
function run()
{
i_take_10_sec()
.then((result) => {
console.log(result);
return i_take_1_sec()
})
.then((result) => {
console.log(result);
return i_take_5_sec()
})
.then((result) => {
console.log(result);
return i_take_7_sec()
})
.then((result)=>{
console.log(result);
})
}
run();
</script>
</body>
</html>
使用promise.html名稱儲存檔案,然後在任何瀏覽器(Chrome,Firefox或IE)中開啟它。 它應該顯示為
如上例所示,每個函式都返回一個使用“ .then()”連結到下一個的promise。 在這種情況下,程式碼流顯得更漂亮和易於理解。
現在考慮一種promise被拒絕的情況。 因此,在那種情況下,它將引發錯誤,並且不會呼叫其他連結的函式呼叫。
讓我們修改上面編寫的程式,並且拒絕來自函式“ i_take_5_sec()”的promise,如下所示:
<html>
<body> Demonstrating promise in javascript:</br>
<script type="text/javascript">
function i_take_10_sec()
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 1 and I take 10 seconds');
}, 10000);
})
}
function i_take_1_sec()
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 2 and I take 1 second');
}, 1000);
})
}
function i_take_5_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
reject('I was no: 3 and I take 5 second')
}, 5000);
})
}
function i_take_7_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 4 and I take 7 second')
}, 7000);
})
}
function run()
{
i_take_10_sec()
.then((result) => {
console.log(result);
return i_take_1_sec()
})
.then((result) => {
console.log(result);
return i_take_5_sec()
})
.then((result) => {
console.log(result);
return i_take_7_sec()
})
.then((result)=>{
console.log(result);
})
}
run();
</script>
</body>
</html>
命名為promise.html並儲存檔案,然後在任何瀏覽器(Chrome,Firefox或IE)中開啟它。 它應該顯示為
從上面的螢幕截圖可以看出,JavaScript在呼叫方法“ i_take_5_sec”後引發了“Uncaught”錯誤,並且沒有其他程式碼語句執行。 因此,這證實了,promise一旦“rejected”了,它將導致所有進一步連結的命令失敗。
如何在JavaScript中使用promise?
通過使用.then,.catch和.finally方法註冊函式來消費promise。 Promise物件用作執行程式和消費函式之間的連結,執行器和接收函式將接收結果或錯誤,並且使用函式可以使用.then,.catch或.finally方法中的任何一種。 讓我們在以下各節中檢視所有這些方法的用法:
如何使用.then()作為消費者函式?
.then()方法在一個promise明確resolved或rejected時呼叫。 其語法如下所示:
語法:
.then(function(result){
//statements when the promise is resolved successfully
}, function(error){
//statements when the prmise was rejected or raised an error
})
通過下圖,我們可以瞭解“ .then()”方法的主要用法:
讓我們以這種方式理解,假設一條if-else語句,其中當給定條件為true時,if塊中的程式碼將執行; 否則,它將執行else塊。 同樣,“ then”方法將使用兩個函式作為引數,第一個函式將在promise成功解決後執行,或者在promise拒絕或引發錯誤時執行第二個方法。
通過修改上面編寫的程式,讓我們瞭解“ .then()消費者方法”的用法和實現:
<html>
<body> Demonstrating promise consumer using .then() method in javascript:</br>
<script type="text/javascript">
function i_take_10_sec()
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 1 and I take 10 seconds');
}, 10000);
})
}
function i_take_5_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
reject('I was no: 3 and I take 5 second')
}, 5000);
})
}
function run()
{
i_take_10_sec()
.then((result) => {
console.log(result);
return i_take_5_sec()
})
.then((result)=>{
console.log(result);
},()=>{
console.log('Error Raised')
})
}
run();
</script>
</body>
</html>
儲存名稱為promiseThen.html的檔案,然後在任何瀏覽器(Chrome,Firefox或IE)中開啟它。 它應該將輸出顯示為:
從上面的螢幕截圖中我們可以看到,由於“ i_take_5_sec()”方法導致承諾被拒絕,因此run方法中的呼叫流呼叫了第二個函式,而不是第一個函式。 因此,以這種方式,使用者可以根據promise的預期輸出,使用“ .then()”方法控制程式的執行流程。
但是,傳遞兩個函式作為then方法的引數看起來有些混亂。 因此,為克服此問題,引入了“ .catch”塊或函式,當出現拒絕或發生某些錯誤時,catch塊將顯式處理。
如何使用.catch()作為消費者函式?
當承諾被拒絕或執行中發生錯誤時,.catch()方法將呼叫。 其語法如下所示:
語法:
.catch(function(error){
//Statements to handle error raised
})
下圖可以幫助您理解“ .catch()”方法的基本用法:
從上圖可以明顯看出,在指定.catch()方法的情況下,當承諾被拒絕時,它將呼叫“ .catch”塊。
讓我們通過如下修改上述編寫的程式來了解“ .catch()消費者函式”的用法和實現:
<html>
<body> Demonstrating promise consumer using .catch() method in javascript:</br>
<script type="text/javascript">
function i_take_10_sec()
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 1 and I take 10 seconds');
}, 10000);
})
}
function i_take_5_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
reject('I was no: 3 and I take 5 second')
}, 5000);
})
}
function run()
{
i_take_10_sec()
.then((result) => {
console.log(result);
return i_take_5_sec()
})
.then((result)=>{
console.log(result);
}).catch(()=>{
console.log('Error Raised')
})
}
run();
</script>
</body>
</html>
使用名稱promiseCatch.html儲存檔案,然後在任何瀏覽器(Chrome,Firefox或IE)中開啟檔案。 它應該將輸出顯示為:
從上面的螢幕截圖中我們可以看到,由於“ i_take_5_sec()”方法導致承諾被拒絕,因此呼叫流程引發了異常,該異常發生在.catch()塊中。 另外,由於異常發生得當,它不會阻止呼叫流程,並且仍然會執行“ Done”列印所產生的.then()部分中的下一部分。 很明顯,即使中間呼叫之一導致錯誤或異常,使用.catch()塊也可以確保繼續執行進一步的連結呼叫。
如何使用.finally()作為消費者者函式?
我們過去經常使用在try{...}catch{...}語句中使用finally塊,在promises也有finally。當promise完成後這個消費者函式總是會執行,無論是resolve或者reject。finally塊是執行清理操作的良好處理程式,我們一直希望執行該處理程式。其語法如下所示:
.finally(() => {
// Statements which are expected to be executed always
})
下圖可以幫助您理解“ .finally()”方法的基本用法:
從上圖可以看出,無論promise是否resolved或者rejected,“ finally”塊始終都會執行。
通過修改上面編寫的程式,讓我們在“ .finally()消費者方法”的用法和實現下進行以下操作:
<html>
<body> Demonstrating promise consumer using .finally() method in javascript:</br>
<script type="text/javascript">
function i_take_10_sec()
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('I was no: 1 and I take 10 seconds');
}, 10000);
})
}
function i_take_5_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
reject('I was no: 3 and I take 5 second')
}, 5000);
})
}
function run()
{
i_take_10_sec()
.then((result) => {
console.log(result);
return i_take_5_sec()
})
.then((result)=>{
console.log(result);
}).catch(()=>{
console.log('Error Raised')
}).finally(()=>{
console.log('Completed Execution')
})
}
run();
</script>
</body>
</html>
儲存名稱為promiseFinally.html的檔案,然後在任何瀏覽器(Chrome,Firefox或IE)中開啟它。 它應該將輸出顯示為:
從上面的螢幕截圖中我們可以看到,由於“ i_take_5_sec()”方法導致承諾被拒絕,因此引發了異常,並且未執行“ Done”塊的下一個.then()方法。 但是,仍然可以從輸出中看到執行了finally()塊。 因此,很清楚,無論promise返回已解決,已拒絕還是錯誤狀態,都將始終執行“ finally()”塊。
如何使用Promise.all()作為消費者函式?
如果你需要並行執行多個promise,並且想要在所有promise完成之後繼續執行,則可以使用JavaScript中Promises提供的“ .all”函式。 它接受一個promises函式陣列,並同時/並行執行所有函式,然後等到所有promise都被rejecte或resolve為止。 其語法如下所示:
Promise.all([array of promises]);
通過以下示例,讓我們瞭解“ Promise.all”的用法:
示例:
<html>
<body> Demonstrating promise all() method in javascript:</br>
<script type="text/javascript">
function i_take_10_sec()
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
console.log('I was no: 1 and I take 10 second')
resolve('I was no: 1 and I take 10 seconds');
}, 10000);
})
}
function i_take_5_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
console.log('I was no: 2 and I take 5 second')
resolve('I was no: 2 and I take 5 second')
}, 5000);
})
}
function i_take_7_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
console.log('I was no: 3 and I take 7 second')
resolve('I was no: 3 and I take 7 second')
}, 7000);
})
}
function run()
{
Promise.all([i_take_10_sec(),i_take_5_sec(),i_take_7_sec()]).then(()=>{
console.log("All finished");
})
}
run();
</script>
</body>
</html>
儲存名稱為promiseAll.html的檔案,然後在任何瀏覽器(Chrome,Firefox或IE)中開啟它。 它應該將輸出顯示為:
我們可以看到,所有的promise都在同時執行,並且會等到所有promise已經resolve或reject為止。
注意:Promise.all()不能確保promise的任何順序。 它只是並行執行所有promise。
如何使用Promise.race()作為消費者函式?
如果您想並行執行多個promise,但又不想等待所有promise的完成再繼續進行,則可以使用JavaScript中Promises提供的“ .race”函式。 它只是等待任何一個promise的完成,然後首先返回。 它將使用一組promise函式並同時執行所有函式,並等待直到任何一個promise已經resolve或reject為止。 其語法如下所示:
Promise.race([array of promises])
在以下示例的幫助下,我們瞭解“ Promise.race”的用法:
示例:
<html>
<body> Demonstrating promise race() method in javascript:</br>
<script type="text/javascript">
function i_take_10_sec()
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
console.log('I was no: 1 and I take 10 second')
resolve('I was no: 1 and I take 10 seconds');
}, 10000);
})
}
function i_take_5_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
console.log('I was no: 2 and I take 5 second')
resolve('I was no: 2 and I take 5 second')
}, 5000);
})
}
function i_take_7_sec(callback)
{
return new Promise((resolve, reject)=>{
setTimeout(() => {
console.log('I was no: 3 and I take 7 second')
resolve('I was no: 3 and I take 7 second')
}, 7000);
})
}
function run()
{
Promise.race([i_take_10_sec(),i_take_5_sec(),i_take_7_sec()]).then(()=>{
console.log("All finished");
})
}
run();
</script>
</body>
</html>
儲存名稱為promiseRace.html的檔案,然後在任何瀏覽器(Chrome,Firefox或IE)中開啟它。 它應該將輸出顯示為:
在上面的示例中,我們可以看到,一個promise(i_take_5 sec)一旦resolve,它就會從then函式中退出。
重點
- promise可以處理JavaScript中的非同步呼叫。
- 根據非同步呼叫的響應,promise在執行時將處於“pending”狀態,並導致“resolved”或“rejected”。
- promise避免由於巢狀的回撥函式而發生的“回撥地獄”問題。
現在,讓我們轉到下一篇文章“ DOM Manipulation”,那裡我們將介紹JavaScript提供的各種概念/功能,DOM將使用這些概念/功能 可以在執行時動態地進行操作