ES6 Promise 用法講解
- Promise是異步編程的一種解決方案,用於一個異步操作的最終完成(或失敗)及其結果值的表示,比傳統的回調函數方案更加合理。
- Promise是一個構造函數,自己身上有all、reject、resolve這幾個眼熟的方法,原型上有then、catch等同樣很眼熟的方法。
var p = new Promise((resolve, reject)=>{
//做一些異步操作
setTimeout(function(){
console.log('執行完成');
resolve('隨便什麼數據');
}, 2000);
});
Promise的構造函數接收一個參數,是函數,並且傳入兩個參數:resolve,reject,分別表示異步操作執行成功後的回調函數和異步操作執行失敗後的回調函數
用Promise的時候一般是包在一個函數中,在需要的時候去運行這個函數.
function runAsync(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
console.log('執行完成');
resolve('隨便什麼數據');
}, 2000);
});
return p; //在我們包裝好的函數最後,會return出Promise對象,Promise對象上有then、catch方法
}
runAsync() //包在一個函數裏,需要的時候去調用它
- reject的用法:reject的作用就是把Promise的狀態置爲rejected,在then中就能捕捉到,然後執行“失敗”情況的回調
function getNumber(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10); //生成1-10的隨機數
if(num<=5){
resolve(num);
}
else{
reject('數字太大了');
}
}, 2000);
});
return p;
}
getNumber()
.then(
function(data){
console.log('resolved');
console.log(data);
},
function(reason, data){
console.log('rejected');
console.log(reason);
}
);
getNumber函數用來異步獲取一個數字,2秒後執行完成,如果數字小於等於5,我們認爲是“成功”了,調用resolve修改Promise的狀態。否則我們認爲是“失敗”了,調用reject並傳遞一個參數,作爲失敗的原因
運行getNumber並且在then中傳了兩個參數,then方法可以接受兩個參數,第一個對應resolve的回調,第二個對應reject的回調。所以我們能夠分別拿到他們傳過來的數據
- catch的用法:Promise對象除了then方法,還有一個catch方法,它和then的第二個參數一樣,用來指定reject的回調。如果拋出異常了(代碼出錯了),那麼並不會報錯卡死js,而是會進到這個catch方法中。
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
在項目中用到:
save_del() {
return new Promise((resolve, reject) => {
//刪除
if (this.del_stem_arr.length > 0 || this.del_answer_arr.length > 0) {
checkstemdelete
.post(
{
checkStem: this.del_stem_arr,
checkStemInfo: this.del_answer_arr
},
this
)
.then(res => {
console.log(res)
if (res) {
resolve('刪除題目成功')
this.del_stem_arr = []
this.del_answer_arr = []
} else {
reject('刪除題目失敗')
}
})
.catch(() => {
reject('刪除題目失敗')
})
} else {
resolve('無刪除題目')
}
})
},
- all的用法:Promise的all方法提供了並行執行異步操作的能力,並且在所有異步操作執行完後才執行回調
例如一個方法需要調多個接口時,用promise.all更合適
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
}); // 有了all,你就可以並行執行多個異步操作,並且在一個回調中處理所有的返回數據
兩個個異步操作是並行執行的,等到它們都執行完後纔會進到 then 裏面。同時 all 會把所有異步操作的結果放進一個數組中傳給 then
//切菜
function cutUp(){
console.log('開始切菜。');
var p = new Promise(function(resolve, reject){ //做一些異步操作
setTimeout(function(){
console.log('切菜完畢!');
resolve('切好的菜');
}, 1000);
});
return p;
}
//燒水
function boil(){
console.log('開始燒水。');
var p = new Promise(function(resolve, reject){ //做一些異步操作
setTimeout(function(){
console.log('燒水完畢!');
resolve('燒好的水');
}, 1000);
});
return p;
}
Promise
.all([cutUp(), boil()])
.then(function(results){
console.log("準備工作完畢:");
console.log(results);
});
項目中:
//保存
save() {
return new Promise((resolve, reject) => {
let arr = []
this.$refs.checkItem.map(object => {
arr.push(object.validate())
})
Promise.all(arr).then(
async () => {
try {
await this.save_del()
await this.save_updateAddAdd()
resolve('保存成功')
} catch (error) {
reject(error)
}
},
() => {
reject('請填寫所有的必填項')
}
)
})
},
- race的用法: all方法的效果實際上是「誰跑的慢,以誰爲準執行回調」,那麼相對的就有另一個方法「誰跑的快,以誰爲準執行回調」,這就是race方法,這個詞本來就是賽跑的意思。race的用法與all一樣
只不過 all 是等所有異步操作都執行完畢後才執行 then 回調。而 race 的話只要有一個異步操作執行完畢,就立刻執行 then 回調。
注意:其它沒有執行完畢的異步操作仍然會繼續執行,而不是停止。
Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
比如我們可以用race給某個異步請求設置超時時間,並且在超時後執行相應的操作
//請求某個圖片資源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}
//延時函數,用於給請求計時
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('圖片請求超時');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});
requestImg函數會異步請求一張圖片,我把地址寫爲"xxxxxx",所以肯定是無法成功請求到的。timeout函數是一個延時5秒的異步操作。我們把這兩個返回Promise對象的函數放進race,於是他倆就會賽跑,如果5秒之內圖片請求成功了,那麼遍進入then方法,執行正常的流程。如果5秒鐘圖片還未成功返回,那麼timeout就跑贏了,則進入catch,報出“圖片請求超時”的信息