含義
非同步程式設計的一種解決方案。是一個構造物件,代表一個非同步操作。有3種狀態:
pending(進行中)、fulfilled(已成功)、rejected(已失敗)。
狀態變更: pending -> fulfilled、pending -> rejected。
狀態變更後就永久保持這個結果。
基本用法
const p = new Promise((resolved, rejected) => {
if(/*非同步操作成功*/) {
resolved(value);
}else{
rejected(error);
}
});
p.then((value) => console.log('非同步執行成功:' + value), //非同步呼叫回撥寫法1
(error) => console.log('非同步執行失敗:' + error))
p.then((value) => console.log('非同步執行成功:' + value)) //非同步呼叫回撥寫法2
.catch((error) => console.log('非同步執行失敗:' + error))
複製程式碼
pending -> fulfilled執行的結果是resolved,
pending -> rejected執行的結果是rejected。
用法
then() catch()
基本用法中的寫法1和寫法2的效果一樣,主要是因為promise.prototype.then() 有兩個引數,第一個引數是 resolved 的回撥,第二個引數(可選)是 rejected 的回撥。
而promise.prototype.catch()主要用來捕獲非同步操作丟擲的錯誤,與try{}catch(){}中的catch功能一樣。promise.prototype.catch()除了能夠捕獲非同步操作中的錯誤外,還能捕獲.then()回撥中的錯誤。
const p = new Promise((resolved, rejected)=>resolved('resolved')).then((value) => {
throw new Error(value);
}, (error) => {})
.catch((error) => console.log(error))
複製程式碼
輸出結果為
另外,當Promise狀態已變成resolved之後再丟擲錯誤,丟擲的錯誤是無效的,同樣以上面的例子為例。
const p = new Promise((resolved, rejected) => {
resolved('resolved');
throw new Error('hhh');
}).then((value) => {
throw new Error(value);
}, (error) => {})
.catch((error) =>console.log(error))
複製程式碼
輸出結果
與上面的結果一致。原因: Promise的狀態變更後就永久保持這個結果,不會再變化了。 .catch()返回的仍是一個Promise物件,在執行.catch之後,仍可以繼續呼叫。
const p = new Promise((resolved, rejected) => {
resolved('hhh');
}).then((value) => {
throw new Error(value);
})
.catch((error) =>console.log(error))
.then(() => console.log('hhhhh'))
複製程式碼
輸出結果:
錯誤捕獲
.catch()具有冒泡的性質,會一直向後傳遞,直到被捕獲為止,也就是說錯誤總會被下一個catch捕獲。.catch()也能捕獲前一個.catch()丟擲的錯誤。
const p = new Promise((resolved, rejected) => {
resolved('hhh');
}).then((value) => {
throw new Error(value);
})
.catch((error) =>{
console.log(r)})
throw new Error('hhhh')
.catch((error) => console.log(error))
複製程式碼
輸出結果:
注意:一般不要使用.then()的第二個引數
舉例:
p.then((value) => { //寫法1
throw new Error(value);
}).catch((error) =>console.log(error))
p.then((value) => { //寫法2
throw new Error(value);
}, (error) => console.log(error))
複製程式碼
寫法1能夠捕獲前面then()中丟擲的錯誤,但寫法2不行
由於.catch()的冒泡性質,當一個promise函式體未對錯誤進行捕獲並進行處理,執行後不會有任何輸出,但是瀏覽器會列印報錯。
Node有一個事件unhandledRejection,專門用來監聽未捕獲的reject錯誤。
process.on('unhandledRejection', (err, p) => {})
複製程式碼
unhandledRejection有兩個引數:
err:錯誤物件
p:報錯的Promise例項
Promise.all([])
Prmise.all()用於將多個Promise例項包裝成一個新的promise例項。
語法: var p = Promise.all([p1,p2,p3])
p1,p2,p3必須都是Promise例項。若其引數不是Promise例項,則會通過Promise.resolve()將其轉為Promise例項再傳給Promise.all()
p的狀態由p1,p2,p3決定:
1、p1,p2,p3狀態都變為Fulfilled,p的狀態才變為Fulfilled。
2、p1,p2,p3中有任一個狀態變為Rejected,p的狀態就變為Rejected。
注意:若作為引數的Promise例項自身定義了catch,則它被rejected並不會觸發Promise.all()的catch()。
const p1 = new Promise((resolved) => {
resolved('hhh');
}).then((value) => value)
.catch((error) => error);
const p2 = new Promise(() => {
throw new Error('hhhhh');
}).then((value) => value)
.catch((error) => error);
Promise.all([p1, p2]).then((result) => console.log(result))
.catch((error) => console.log(error));
複製程式碼
輸出:走到了Promise的then(),正常輸出
Promise.race()
跟上面的Promise.all()一樣,都是將多個Promise例項包裝成一個新的Promise例項 Promise.resolve()
語法: var p = Promise.race([p1,p2,p3])
p的狀態由p1,p2,p3中最先改變狀態的例項決定。
Promise.resolve()
作用: 將先有的物件轉為Promise物件。
let foo = () => console.log('foo')
Promise.resolve(foo)
複製程式碼
等價於
new Promise((resolve) => resolve(foo));
複製程式碼
引數:
1、Promise例項:不做任何修改,直接返回該例項
2、帶有then()的物件:將這個物件轉為Promise物件並立即執行then方法。
let foo ={
then : (resolve) => resolve('foo')
}
let p1 = Promise.resolve(foo)
p1.then((value) => console.log(value))
複製程式碼
這裡會輸出'foo',因為p1會立即執行foo的then方法,執行後p1的狀態才變為resolved。
這個用法比較常用,當非同步呼叫多個介面改變資料,但後面需要同時處理改變後的這些資料時,可結合Promise.all和Promise.resolve()來使用。
3、引數不是物件
Promise.resolve('foo');
該用法在Promise例項生成時狀態就為Resolved,所有回撥函式會立即執行,並將引數傳給Promise的回撥函式。
4、不帶引數:返回一個空Promise例項
注意:Promise.resolve()是在本輪"事件迴圈"結束時執行
因為setTimeout是在下輪“事件迴圈”開始時執行,console.log(3)立即執行,因此有了這樣的輸出結果。
Promise.reject()
返回一個新的Promise例項,狀態為rejected。
該方法的引數會被原封不動的傳給Promise.catch()作為引數。不區分該引數型別。
.done()
處於回撥鏈的低端,保證能夠接收丟擲的任何可能的錯誤。
.finally()
用於指定不管Promise物件最後狀態如何都會執行的操作。它接收的回撥函式作為引數。
比如:呼叫介面時會對介面做處理,不論介面呼叫成功還是失敗,都要做出提示,那麼就可以用這個方法用來做提示的回撥。
.try()
實際中會遇到不知道或者不想區分回撥函式是同步的還是非同步的,但是想用Promise
處理,因為這樣就可以不管回撥函式是同步還是非同步,都能使用then()指定下一步操作,用catch捕獲錯誤。
Promise.try()的作用就是解決上面的問題。
以上,屬於個人學習promise之後對promise的簡單理解。