. 前沿
小編一直在項目中使用promise,,但是對promise理解的不是很透徹,總是模棱兩可的,所以用的不是很得心應(yīng)手,最近幸得與空,好好總結(jié)學(xué)習(xí)一下,經(jīng)過研究總結(jié)下來,發(fā)現(xiàn)自己一下清晰了好多,不錯很有幫助,不過這里都是我自己的理解,可能還有一些不足的地方,還要多多學(xué)習(xí),以后還會更新不足的或者錯誤的地方。
. 一,首先說一下Promise的概念
Promise是異步編程的一種解決方案,說白了就是一個構(gòu)造函數(shù),他自己本身有
race,all,reject,resolve這幾個方法,原型上有then,catch兩個方法。
二,Promise對象的特點:
- 1, 對象的狀態(tài)不受外界影響,promise對象代表一個異步操作,它有三種狀態(tài),pending(進行中)、fulfilled(已成功)、rejected(已失敗)。只有異步操作的結(jié)果可以決定當(dāng)前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài),這也是(承諾)這個名字的由來。
- 2, 一旦狀態(tài)改變就不會在改變,任何時候都可以得到這個結(jié)果,promise對象狀態(tài)改變的過程只能是:從
pending變?yōu)?code>fulfilled還有從pending變?yōu)?code>rejected.也就是說如果狀態(tài)發(fā)生上述變化后,狀態(tài)就不會在改變了,這個時候我們稱之為resolved已定型。 - 3, 這就是與事件
event不同的地方,事件是如果你錯過了,再去監(jiān)聽是得不到結(jié)果的。
三,Promise的用法:
- 1, 首先它是一個構(gòu)造函數(shù),所以每當(dāng)我們
new一個promise實例,就表示一個具體的異步操作,這個構(gòu)造函數(shù)里邊有兩個參數(shù),分別是:resolve(成功之后的回調(diào)函數(shù))和reject(失敗之后的回調(diào)函數(shù))。 - 2,所以說這個異步操作的結(jié)果就是
失敗或者成功,兩者都需要回調(diào)函數(shù)reject/resolve返回,這里要注意的是跟之前的單純的回調(diào)函數(shù)不同,不能用return把操作結(jié)果返回。要用回調(diào)函數(shù),切記。
. 我個人覺得這玩意還是需要舉例子比較好理解一點。我在我的項目中寫了一個例子,用來理解promise,
接下來我們先new一個Promise對象
//我是在vue項目中
mounted() {
let textPromise = new Promise((resolve, reject) => {
//這個時候我們做一些異步操作
setTimeout(() => {
console.log("執(zhí)行完成我測試的promise");
resolve('這里的resolve是成功后的回調(diào)');
}, 3000);
});
},
執(zhí)行上面的代碼,就會發(fā)現(xiàn)控制臺直接打出
執(zhí)行完成我測試的promise這里需要注意的是我只是new了一個對象,并沒有調(diào)用它,但是我寫在里邊的異步操作已經(jīng)執(zhí)行了,所以說當(dāng)我們使用
Promise時,需要寫在一個函數(shù)中,在需要的時候再去運行這個函數(shù),舉個例子:
<div @click="shishi"></div>
methods:{
shishi() {
console.log("點擊方法被調(diào)用");
this.promiseTest().then((data) => {
console.log(data);
})
},
promiseTest() {
let textPromise = new Promise((resolve, reject) => {
//這個時候我們做一些異步操作
setTimeout(() => {
console.log("執(zhí)行完成我測試的promise");
resolve('這里的resolve是成功后的回調(diào)');
}, 3000);
});
return textPromise;
},
}
看完上面的代碼是不是你自己就有了一些理解了
在promiseTest方法里邊 return textPromise;出來這個對象,那么接下來就可以在
shishi()方法里邊使用Promise對象上的then和catch方法了,這里就表現(xiàn)出來promise的強大之處了。
- 這個時候你就應(yīng)該有一些小小的領(lǐng)悟就是原來then里邊的函數(shù)跟我們平時的一個回調(diào)函數(shù)是一個意思,它接受
resolve傳過來的數(shù)據(jù),可以在shishi這個點擊方法執(zhí)行完成之后在執(zhí)行textPromise的回調(diào)函數(shù)。 -
promise的好處就是當(dāng)有多層回調(diào)時,可以不斷的在then方法中繼續(xù)寫promise對象并返回,然后在then方法中進行回調(diào)操作。
所以說promise的精髓就是能夠簡化層層回調(diào),直接在后邊鏈式回調(diào)then,比你不斷的寫callback方法要好的多,也就達到了異步的效果。
所以說promise的正確應(yīng)用場景是
<div @click="shishi"></div>
methods:{
shishi() {
this.promiseTest().then((data) => {
//這里的data就是promiseTest中textPromise對象中resolve回調(diào)方法中返回的值
console.log(data);
//然后在這里在把this.promiseTestOne(data);的結(jié)果回調(diào)給下一個dataOne
//這里如同回調(diào)函數(shù),把第二個的方法傳過去才會運行,如果在這里只return,data,那么打印的結(jié)果就是
全是第一個promise里resolve('這里的resolve是成功后的回調(diào)');的值。
return this.promiseTestOne(data);
}, (reject) => {
console.log(reject); //這里就是錯誤的回調(diào),但是盡量不要寫在這里,而是寫在catch里
}).then((dataOne) => {
//這里的dataOne就是promiseTestOne中textPromise1對象中resolve回調(diào)方法中返回的值
console.log(dataOne);
}).then((data) =>{
console.log(data); //同樣這個data還是接受的上個promise中resolve回調(diào)的值
console.log("前邊倆方法都調(diào)用成功后才會走這個");
}).catch((data) => {
//一般情況下你的方法出錯不會卡死,而是進入這里。
console.log(data); //catch就是用來捕獲異常的,所以一般錯誤都會在這里輸出日志
})
},
promiseTest() {
let textPromise = new Promise((resolve, reject) => {
//這個時候我們做一些異步操作
setTimeout(() => {
console.log("執(zhí)行完成我測試的promise");
resolve('這里的resolve是成功后的回調(diào)');
//下邊這段代碼會執(zhí)行在reject或者catch中
let a = 10;
if (a == 10) {
reject('這里的reject是失敗后的回調(diào)');
}
}, 3000);
});
return textPromise;
},
promiseTestOne(data) {
//data是接受的第一個promise中的回調(diào)值,方便這個promise使用
console.log("我是第二個方法" + data + "data 是從promiseTest 的resolve 回調(diào)傳過來的值");
let textPromise1 = new Promise((resolve, reject) => {
//這個時候我們做一些異步操作
setTimeout(() => {
console.log("執(zhí)行完成我測試的promise 測試11");
resolve('這里的resolve是成功后的回調(diào)' + '測試1');
}, 3000);
});
return textPromise1;
},
}
以上寫法就達到了你想在某個接口完全完成之后在調(diào)用下一個接口,也就是異步調(diào)用,而不是像你之前那樣,同步的調(diào)用接口。
其實上邊的代碼跟注釋就一同解釋了
promise的reject、resolve、then、catch、這幾個方法
接下來說一下all方法,all是跟then方法同級的一個方法,該方法提供了并行執(zhí)行(也就是多個方法可以共存并且同時執(zhí)行)異步操作的能力,就是說在所有的異步操作執(zhí)行完成后并且都是成功的情況下才會執(zhí)行回調(diào)。
- 也就是說all方法不適合我上邊舉的例子,all方法適合在多個互不相關(guān)的方法需要同時執(zhí)行成功后在執(zhí)行某方法時使用
shishi() {
Promise.all([this.promiseTest(),this.promiseTestOne()]).then((allResult) => {
console.log(allResult);
console.log("所有的異步操作執(zhí)行完成后并且都是成功的情況下才會執(zhí)行回調(diào)");
}).catch((catchResult)=>{
console.log(catchResult);
})
},
promiseTest() {
let textPromise = new Promise((resolve, reject) => {
//這個時候我們做一些異步操作
setTimeout(() => {
console.log("執(zhí)行完成我測試的promise")
resolve('這里的resolve是成功后的回調(diào)');
}, 3000);
});
return textPromise;
},
promiseTestOne() {
let textPromise1 = new Promise((resolve, reject) => {
//這個時候我們做一些異步操作
setTimeout(() => {
console.log("執(zhí)行完成我測試的promise 測試11");
resolve('這里的resolve是成功后的回調(diào)' + '測試1');
}, 3000);
});
return textPromise1;
},
里邊的注釋看完是不是一目了然。
最后再說一下不常用的race方法
race其實是和all是相反的,就是誰先執(zhí)行完,就先走誰的回調(diào),舉個例子,一目了然
注意我把異步的時間改一下
shishi() {
Promise.race([this.promiseTest(),this.promiseTestOne()]).then((allResult) => {
console.log(allResult);
console.log("誰先執(zhí)行完,就先走誰的回調(diào)");
}).catch((catchResult)=>{
console.log(catchResult);
})
},
promiseTest() {
let textPromise = new Promise((resolve, reject) => {
//這個時候我們做一些異步操作
setTimeout(() => {
console.log("執(zhí)行完成我測試的promise")
resolve('這里的resolve是成功后的回調(diào)');
}, 2000);
});
return textPromise;
},
promiseTestOne() {
let textPromise1 = new Promise((resolve, reject) => {
//這個時候我們做一些異步操作
setTimeout(() => {
console.log("執(zhí)行完成我測試的promise 測試11");
resolve('這里的resolve是成功后的回調(diào)' + '測試1');
}, 5000);
});
return textPromise1;
},
上面的代碼執(zhí)行結(jié)果就是2秒的先執(zhí)行完畢就已經(jīng)進入到then里面的了,而于此同時,promiseTestOne也就是5秒的并沒有停止,還在運行,于是在過三秒后,輸出了各自的回調(diào)值。
結(jié)束語
最后再說一下,race方法的用法,小編很少用到,所以等慢慢接觸到在更新,目前常用的5種。