歡迎大家前往 "騰訊雲+社區" ,獲取更多騰訊海量技術實踐乾貨哦~ 本文由 "前端林子" 發表於 "雲+社區專欄" Promise是CommonJS提出的一種規範,在ES6中已經原生支持Promise對象,非ES6環境可以用Bluebird等庫來支持。 0.引入 在js中任務的執行模型有兩種:同步模 ...
歡迎大家前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~
Promise是CommonJS提出的一種規範,在ES6中已經原生支持Promise對象,非ES6環境可以用Bluebird等庫來支持。
0.引入
在js中任務的執行模型有兩種:同步模式和非同步模式。
同步模式:後一個任務B等待前一個任務A結束後,再執行。任務的執行順序和任務的排序順序是一致的。
非同步模式:每一個任務有一個或多個回調函數,前一個任務A結束後,不是執行後一個任務B,而是執行任務A的回調函數。而後一個任務B是不等任務A結束就執行。任務的執行順序,與任務的排序順序不一致。
非同步模式編程有四種方法:回調函數(最基本的方法,把B寫成A的回調函數)、事件監聽(為A綁定事件,當A發生某個事件,就執行B)、發佈/訂閱,以及本文要介紹的Promise對象。
Promise是一個用於處理非同步操作的對象,可以將回調函數寫成鏈式調用的寫法,讓代碼更優雅、流程更加清晰,讓我們可以更合理、更規範地進行非同步處理操作。它的思想是,每一個非同步任務返回一個Promise對象,該對象有一個then方法,允許指定回調函數。
1.Promise的基本知識
1.1 三種狀態
Pending:進行中,剛創建一個Promise實例時,表示初始狀態;
resolved(fulfilled):resolve方法調用的時候,表示操作成功,已經完成;
Rejected:reject方法調用的時候,表示操作失敗;
1.2 兩個過程
這三種狀態只能從pendeng-->resolved(fulfilled),或者pending-->rejected,不能逆向轉換,也不能在resolved(fulfilled)和rejected之間轉換。並且一旦狀態改變,就不會再改變,會一直保持這個結果。
彙總上述,創建一個Promise的實例是這樣的:
//創建promise的實例
let promise = new Promise((resolve,reject)=>{
//剛創建實例時的狀態:pending
if('非同步操作成功'){
//調用resolve方法,狀態從pending變為fulfilled
resolve();
}else{
//調用reject方法,狀態從pending變為rejected
reject();
}
});
1.3 then()
用於綁定處理操作後的處理程式,分別指定fulfilled狀態和rejected狀態的回調函數,即它的參數是兩個函數,第一個用於處理操作成功後的業務,第二個用於處理操作失敗後的業務。
//then()
promise.then((res)=> {
//處理操作成功後的業務(即Promise對象的狀態變為fullfilled時調用)
},(error)=> {
//處理操作失敗後的業務(即Promise對象的狀態變為rejected時調用)
});
1.4 catch()
用於處理操作異常的程式,catch()只接受一個參數
//catch()
promise.catch((error)=> {
//處理操作失敗後的業務
});
一般來說,建議不要在then()裡面定義rejected狀態的回調函數,而是將then()用於處理操作成功,將catch()用於處理操作異常。因為這樣做可以捕獲then()執行中的錯誤,也更接近同步中try/catch的寫法:
//try-catch
// bad
promise.then((res)=> {
//處理操作成功後的業務
}, (error)=> {
//處理操作失敗後的業務
});
// good
promise
.then((res)=> {
//處理操作成功後的業務
})
.catch((error)=> {
//處理操作失敗後的業務
});
1.5 all()
接受一個數組作為參數,數組的元素是Promise實例對象。只有當參數中的實例對象的狀態都為fulfilled時,Promise.all( )才會有返回。
實例代碼(可直接在瀏覽器中打開):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise實例</title>
<style type="text/css"></style>
<script type="text/javascript">
window.onload = () => {
//創建實例promise1
let promise1 = new Promise((resolve) => {
setTimeout(() => {
resolve('promise1操作成功');
console.log('1')
}, 3000);
});
//創建實例promise1
let promise2 = new Promise((resolve) => {
setTimeout(() => {
resolve('promise1操作成功');
console.log('2')
}, 1000);
});
Promise.all([promise1, promise2]).then((result) => {
console.log(result);
});
}
</script>
</head>
<body>
<div></div>
</body>
</html>
結果(註意看時間):
Promise.all()
代碼說明:
1s後,promise2進入fulfilled狀態,間隔2s,也就是3s後,promise1也進入fulfilled狀態。這時,由於兩個實例都進入了fulfilled狀態,所以Promise.all()才進入了then方法。
使用場景:執行某個操作需要依賴多個介面請求回的數據,且這些介面之間不存在互相依賴的關係。這時使用Promise.all(),等到所有介面都請求成功了,它才會進行操作。
1.6 race()
和all()的參數一樣,參數中的promise實例,只要有一個狀態發生變化(不管是成功fulfilled還是異常rejected),它就會有返回,其他實例中再發生變化,它也不管了。
實例代碼(可直接在瀏覽器中打開):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise實例</title>
<style type="text/css"></style>
<script type="text/javascript">
window.onload = () => {
//創建實例promise1
let promise1 = new Promise((resolve) => {
setTimeout(() => {
resolve('promise1操作成功');
console.log('1')
}, 3000);
});
//創建實例promise1
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('promise1操作失敗');
console.log('2')
}, 1000);
});
Promise.race([promise1, promise2])
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error);
})
}
</script>
</head>
<body>
<div></div>
</body>
</html>
結果(註意看時間):
Promise.race()
代碼說明:
1s後,promise2進入rejected狀態,由於一個實例的狀態發生了變化,所以Promise.race()就立刻執行了。
2 實例
平時開發中可能經常會遇到的問題是,要用ajax進行多次請求。例如現在有三個請求,請求A、請求B、請求C。請求C要將請求B的請求回來的數據做為參數,請求B要將請求A的請求回來的數據做為參數。
按照這個思路,我們可能會直接寫出這樣的層層嵌套的代碼:
//------請求A 開始---------
$.ajax({
success:function(res1){
//------請求B 開始----
$.ajax({
success:function(res2){
//----請求C 開始---
$.ajax({
success:function(res3){
}
});
//---請求C 結束---
}
});
//------請求B 結束-----
}
});
//------請求A 結束---------
在請求A的success後,請求B發送請求,在請求B 的success後,請求C發送請求。請求C結束後,再向上到請求B結束,請求B結束後,再向上到請求A結束。
這樣雖然可以完成任務,但是代碼層層嵌套,代碼可讀性差,也不便於調試和後續的代碼維護。而如果用Promise,你可以這樣寫(示意代碼,無ajax請求):
此處附上完整可執行代碼,可在瀏覽器的控制臺中查看執行結果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise實例</title>
<style type="text/css"></style>
<script type="text/javascript">
window.onload = () => {
let promise = new Promise((resolve, reject) => {
if (true) {
//調用操作成功方法
resolve('操作成功');
} else {
//調用操作異常方法
reject('操作異常');
}
});
//then處理操作成功,catch處理操作異常
promise.then(requestA)
.then(requestB)
.then(requestC)
.catch(requestError);
function requestA() {
console.log('請求A成功');
return '下一個是請求B';
}
function requestB(res) {
console.log('上一步的結果:' + res);
console.log('請求B成功');
return '下一個是請求C';
}
function requestC(res) {
console.log('上一步的結果:' + res);
console.log('請求C成功');
}
function requestError() {
console.log('請求失敗');
}
}
</script>
</head>
<body>
<div></div>
</body>
</html>
結果如下:
實例
可以看出請求C依賴請求B的結果,請求B依賴請求A的結果,在請求A中是使用了return將需要的數據返回,傳遞給下一個then()中的請求B,實現了參數的傳遞。同理,請求B中也是用了return,將參數傳遞給了請求C。
3.小結
本文主要介紹了Promise對象的三個狀態和兩個過程。“三個狀態”是:初始化、操作成功、操作異常,“兩個過程”是初始化狀態到操作成功狀態,和初始化狀態到操作異常狀態。除此之前,還有兩種實例方法:then()、catch()來綁定處理程式。類方法:Promise.all()、Promise.race()。如有問題,歡迎指正。
此文已由作者授權騰訊雲+社區發佈,更多原文請點擊
搜索關註公眾號「雲加社區」,第一時間獲取技術乾貨,關註後回覆1024 送你一份技術課程大禮包!
海量技術實踐經驗,盡在雲加社區!