簡單理解promise

九酒發表於2019-02-25

含義

非同步程式設計的一種解決方案。是一個構造物件,代表一個非同步操作。有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

另外,當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

與上面的結果一致。原因: 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'))
複製程式碼

輸出結果:

簡單理解promise

錯誤捕獲

.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))
複製程式碼

輸出結果:

簡單理解promise

注意:一般不要使用.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函式體未對錯誤進行捕獲並進行處理,執行後不會有任何輸出,但是瀏覽器會列印報錯。

簡單理解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
輸出:走到了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()是在本輪"事件迴圈"結束時執行

簡單理解promise

因為setTimeout是在下輪“事件迴圈”開始時執行,console.log(3)立即執行,因此有了這樣的輸出結果。

Promise.reject()

返回一個新的Promise例項,狀態為rejected。

該方法的引數會被原封不動的傳給Promise.catch()作為引數。不區分該引數型別。

.done()

處於回撥鏈的低端,保證能夠接收丟擲的任何可能的錯誤。

.finally()

用於指定不管Promise物件最後狀態如何都會執行的操作。它接收的回撥函式作為引數。

比如:呼叫介面時會對介面做處理,不論介面呼叫成功還是失敗,都要做出提示,那麼就可以用這個方法用來做提示的回撥。

.try()

實際中會遇到不知道或者不想區分回撥函式是同步的還是非同步的,但是想用Promise

處理,因為這樣就可以不管回撥函式是同步還是非同步,都能使用then()指定下一步操作,用catch捕獲錯誤。

Promise.try()的作用就是解決上面的問題。

以上,屬於個人學習promise之後對promise的簡單理解。

相關文章