Promise
Promise就是ES6新增的一個用于解決異步程式設計的方案。以前,我們在處理異步的時候,都是在回調函數内做處理的。比如Ajax請求,是在success屬性裡面做異步處理的,那麼如果在一個請求中需要執行讀個異步請求,第二個請求是依賴于第一個請求的結果,這樣就導緻代碼嵌套很深,可讀性差、很難維護并且難以複用。
那麼Promise正好可以解決這樣的問題,Promise有3種狀态:pending、fulfilled和rejected。Promise在建立階段是屬于pending狀态,接着狀态隻能有兩種一個數fulfilled或者rejected,狀态改變後就不能再發生變化了,例如:
const promise = new Promise((resolve, rejected) => {
// 異步請求處理
if (/異步請求/) {
resolve();
} else {
rejected();
}
})
異步請求成功,則執行resolve函數,否則執行rejected函數,resolve和rejected函數可以傳參數,作為後面.then函數或者catch函數的資料源。
Promise在建立後立即調用,然後等待執行resolve或者是rejected函數來确定Promise的最終狀态,比如下面代碼:
const promise = new Promise((resolve, rejected) => {
console.log("Promise");
resolve();
})
promise.then(() => {
console.log("resolve")
});
console.log("hello")
結果就是Promise,hello,resolve。因為Promise建立後會立即執行,輸出Promise;然後是執行resolve函數,這樣就會觸發then函數裡面的回調函數,但是它需要等待目前線程代碼執行完畢後再執行,縮回跳過,先執行後面的代碼,輸出hello,最後執行then的回調函數,輸出resolve。
then函數,傳回的是一個Promise對象執行個體,是以可以通過鍊式調用then函數,在上一個then函數内return的值是下一個then函數接收的資料,比如:
const promise = new Promise((resolve, rejected) => {
resolve(1);
})
promise.then((res) => {
console.log(res);
return 2;
}).then(res => {
console.log(res);
return 3;
}).then(res => {
console.log(res)
})
結果就是一次列印1,2,3。這樣就是可以解決異步回調地獄的問題。
catch函數,是Promise執行失敗的回調。如果我們在Promise中手動抛出一個異常,來測試catch函數,代碼如下:
const promise1 = new Promise((resolve, rejected) => {
try {
throw new Error("測試");
} catch (error) {
rejected(error)
}
})
promise1.catch(err=>{
console.log(err); // Error: 測試
})
然而Promise在執行中,如果出現異常就會自動抛出,這樣上面的代碼可以改為:
const promise1 = new Promise((resolve, rejected) => {
throw new Error("測試");
})
promise1.catch(err=>{
console.log(err); // Error: 測試
})
但是需要注意,Promise的狀态一旦變味fulfilled成功狀态,然後再抛出異常,是不能觸發catch的,因為前面已經說過了Promise的狀态隻要發生變化後就不能再次更改。
Promise靜态方法
Promise.all()函數
将多個Promise對象執行個體包裝成為一個Promise執行個體,參數是一個數組,這個Promise的狀态是由所有傳入Promise對象來決定,當所有的Promise的狀态為fulfilled,這個新的Promise的狀态才是fulfilled狀态,如果有一個promise的狀态為rejected,那麼這個新Promise的狀态就是reject。
現在使用一段代碼來了解上面的描述:
const p1 = new Promise((resolve, reject) => {
resolve("success")
})
const p2 = new Promise((resolve, reject) => {
resolve(1)
})
const p = Promise.all([p1, p2]);
p.then(res => {
console.log(res);
}).catch(err => {
console.log(err)
})
// [ 'success', 1 ]
如果p1,p2中已經定義了對應的catch,當有一個promise狀态變為reject的話,promise.all不會觸發catch函數了,比如:
const p1 = new Promise((resolve, reject) => {
resolve("success")
}).then(res => res).catch(err => err)
const p2 = new Promise((resolve, reject) => {
throw new Error("報錯")
}).then(res => res).catch(err => err)
const p = Promise.all([p1, p2]);
p.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
// [ 'success', Error: 報錯 ]
Promise.race 函數
通過race方法來合并多個promise,那麼這個promise狀态是最先更新狀态的promise的狀态,比如:
const p1 = new Promise((resolve, reject) => {
}).then(res => res).catch(err => err)
const p2 = new Promise((resolve, reject) => {
reject("失敗了")
}).then(res => res).catch(err => err)
const race = Promise.race([p1, p2]);
race.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
}) // 失敗了
Promise.any函數
傳入一個可疊代的參數,如數組。
結果為:
1、所有promise狀态都為成功,傳回的是第一個promise的成功狀态
//1.擷取輪播資料清單
function getBannerList() {
return new Promise((resolve, reject) => {
resolve('banner')
})
}
//2.擷取店鋪清單
function getStoreList() {
return new Promise((resolve, reject) => {
resolve('store')
})
}
//3.擷取分類清單
function getCategoryList() {
return new Promise((resolve, reject) => {
resolve("失敗了")
})
}
function initLoad() {
Promise.any([getBannerList(), getStoreList(), getCategoryList()])
.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
}
initLoad(); // banner
//1.擷取輪播資料清單
function getBannerList() {
return new Promise((resolve, reject) => {
reject('banner')
})
}
//2.擷取店鋪清單
function getStoreList() {
return new Promise((resolve, reject) => {
resolve('store')
})
}
//3.擷取分類清單
function getCategoryList() {
return new Promise((resolve, reject) => {
resolve("失敗了")
})
}
function initLoad() {
Promise.any([getBannerList(), getStoreList(), getCategoryList()])
.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
}
initLoad(); // store
//1.擷取輪播資料清單
function getBannerList() {
return new Promise((resolve, reject) => {
reject('banner')
})
}
//2.擷取店鋪清單
function getStoreList() {
return new Promise((resolve, reject) => {
reject('store')
})
}
//3.擷取分類清單
function getCategoryList() {
return new Promise((resolve, reject) => {
reject("失敗了")
})
}
function initLoad() {
Promise.any([getBannerList(), getStoreList(), getCategoryList()])
.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
}
initLoad(); // [AggregateError: All promises were rejected]