es6 promise

寫過javascript的童鞋也一定都寫過回調方法(callback),簡單說回調方法就是將一個方法func2作爲參數傳入另一個方法func1中,當func1執行到某一步或者滿足某種條件的時候才執行傳入的參數func2,例如下面的代碼段

// 當參數a大於10且參數func2是一個方法時 執行func2
function func1(a, func2) {
    if (a > 10 && typeof func2 == 'function') {
        func2()
    }
}

func1(11, function() {
    console.log('this is a callback')
})

一般來說我們會碰到的回調嵌套都不會很多,一般就一到兩級,但是某些情況下,回調嵌套很多時,代碼就會非常繁瑣,會給我們的編程帶來很多的麻煩,這種情況俗稱——回調地獄。極端情況如下圖:

 

由此,Promise的概念就由社區提出並實現,作用與回調方法幾乎一致,都是在某種情況下執行預先設定好的方法,但是使用它卻能夠讓代碼變得更簡潔清晰

什麼是Promise

Promise是異步編程的一種解決方案,它有三種狀態,分別是pending-進行中resolved-已完成rejected-已失敗

當Promise的狀態由pending轉變爲resolved或rejected時,會執行相應的方法,並且狀態一旦改變,就無法再次改變狀態,這也是它名字promise(承諾)的由來

ES6之前的Promise

在ES6中,Promise終於成爲了原生對象,可以直接使用。但是在這之前,想要使用Promise,一般會藉助於第三方庫,或者當你知道其中的原理以後,也可以手動實現一個簡易的Promise

當然,爲了防止不可預知的bug,在生產項目中最好還是不要使用原生的或者自己編寫的Promise(目前爲止並不是所有瀏覽器都能很好的兼容ES6),而是使用已經較爲成熟的第三方Promise庫,下面就爲小夥伴推薦一個—— Bluebird

Promise的基本用法

聲明一個Promise對象

// 方法1
let promise = new Promise ( (resolve, reject) => {
    if ( success ) {
        resolve(a) // pending ——> resolved 參數將傳遞給對應的回調方法
    } else {
        reject(err) // pending ——> rejectd
    }
} )

// 方法2
function promise () {
    return new Promise ( function (resolve, reject) {
        if ( success ) {
            resolve(a)
        } else {
            reject(err)
        }
    } )
}

注意:實例化的Promise對象會立即執行

Promise.prototype.then() VS Promise.prototype.catch()

.then()方法是Promise原型鏈上的方法,它包含兩個參數方法,分別是已成功resolved的回調和已失敗rejected的回調

promise.then(
    () => { console.log('this is success callback') },
    () => { console.log('this is fail callback') }
)

.catch()的作用是捕獲Promise的錯誤,與then()的rejected回調作用幾乎一致。但是由於Promise的拋錯具有冒泡性質,能夠不斷傳遞,這樣就能夠在下一個catch()中統一處理這些錯誤。同時catch()也能夠捕獲then()中拋出的錯誤,所以建議不要使用then()的rejected回調,而是統一使用catch()來處理錯誤

promise.then(
    () => { console.log('this is success callback') }
).catch(
    (err) => { console.log(err) }
)

同樣,catch()中也可以拋出錯誤,由於拋出的錯誤會在下一個catch中被捕獲處理,因此可以再添加catch()

使用rejects()方法改變狀態和拋出錯誤 throw new Error() 的作用是相同的

當狀態已經改變爲resolved後,即使拋出錯誤,也不會觸發then()的錯誤回調或者catch()方法

then() 和 catch() 都會返回一個新的Promise對象,可以鏈式調用

promise.then(
    () => { console.log('this is success callback') }
).catch(
    (err) => { console.log(err) }
).then(
    ...
).catch(
    ...
)

Promise實例的異步方法和then()中返回promise有什麼區別?

// p1異步方法中返回p2
let p1 = new Promise ( (resolve, reject) => {
    resolve(p2)
} )
let p2 = new Promise ( ... )

// then()中返回promise
let p3 = new Promise ( (resolve, reject) => {
    resolve()
} )
let p4 = new Promise ( ... )
p3.then(
    () => return p4
)

p1異步方法中返回p2

p1的狀態取決於p2,如果p2爲pending,p1將等待p2狀態的改變,p2的狀態一旦改變,p1將會立即執行自己對應的回調,即then()中的方法針對的依然是p1

then()中返回promise

由於then()本身就會返回一個新的promise,所以後一個then()針對的永遠是一個新的promise,但是像上面代碼中我們自己手動返回p4,那麼我們就可以在返回的promise中再次通過 resolve() 和 reject() 來改變狀態

Promise的其他api

Promise.resolve() / Promise.reject()

用來包裝一個現有對象,將其轉變爲Promise對象,但Promise.resolve()會根據參數情況返回不同的Promise:

參數是Promise:原樣返回
參數帶有then方法:轉換爲Promise後立即執行then方法
參數不帶then方法、不是對象或沒有參數:返回resolved狀態的Promise

Promise.reject()會直接返回rejected狀態的Promise

Promise.all()

參數爲Promise對象數組,如果有不是Promise的對象,將會先通過上面的Promise.resolve()方法轉換

var promise = Promise.all( [p1, p2, p3] )
promise.then(
    ...
).catch(
    ...
)

當p1、p2、p3的狀態都變成resolved時,promise纔會變成resolved,並調用then()的已完成回調,但只要有一個變成rejected狀態,promise就會立刻變成rejected狀態

Promise.race()

var promise = Promise.race( [p1, p2, p3] )
promise.then(
    ...
).catch(
    ...
)

“競速”方法,參數與Promise.all()相同,不同的是,參數中的p1、p2、p3只要有一個改變狀態,promise就會立刻變成相同的狀態並執行對應的回調。

Promise.done() / Promise. finally()

Promise.done() 的用法類似 .then() ,可以提供resolved和rejected方法,也可以不提供任何參數,它的主要作用是在回調鏈的尾端捕捉前面沒有被 .catch() 捕捉到的錯誤

Promise. finally() 接受一個方法作爲參數,這個方法不管promise最終的狀態是怎樣,都一定會被執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章