前端萌新眼中的Promise及使用

一個 Promise 就是一個表明了異步操做最終完成或者失敗的對象。這是MDN上關於Promise的解釋。在前端開發中,Promise常常被拿來用於處理異步和回調的問題,來規避回調地獄和更好排布異步相關的代碼。本篇文章對於Promise以及相關的async/await記錄一些本身的理解和體會。前端

1、Promise的三種狀態

從字面的意思理解,Promise便是承諾,既是承諾,那承諾的結果就會有成功和失敗兩種。並且,咱們許下承諾以後不會當即獲得結果,在得到成功或是失敗的結果以前,咱們還須要一點時間來履行這個承諾。Promise的構造其實像極了咱們生活中的承諾。ios

Promise

上面這張圖就是Promise的結構圖。就像咱們生活中的承諾同樣,Promise也存在三種狀態,一種是履行承諾的pending狀態,一種是承諾失敗時的Rejected狀態,再就是承諾成功時Fullfilled狀態。axios

接下來,咱們以愛情的名義來承諾一下:數組

let love = new Promise((resolve, reject) => {
    setTimeout(() => {         //開始談戀愛,不過戀愛的結果要之後才知道
        let happy = Math.random() >= 0.3 ? true : false
        if ( happy ) {
            resolve('marry')    //戀愛成功,決定結婚
        } else {
            reject('break')     //戀愛失敗,決定分手
        }    
    }, 500)
})


love.then(result => {
    console.log(result)   //處理戀愛成功的回調,result是上面resolve傳過來的'marry'
}).catch(result => {
    console.log(result)   //處理戀愛失敗的回調,result是上面reject傳過來的'break'
})

複製代碼

上面的代碼就是一個簡單卻完整的Promise的例子。須要特別注意的是,Promise在通過pending狀態達到成功或失敗狀態時就會凝固,即到達成功狀態後不再會失敗,失敗之後也不會回到成功狀態。瀏覽器

因此下面的Promise必定是失敗狀態的,即使reject後面跟了resolve也沒用。正所謂:若愛,請深愛,若棄,請完全,不要曖昧,傷人傷己。柏拉圖這話,說的就是Promise的狀態凝固。bash

let love = new Promise((resolve, reject) => {
    reject('break')
    resolve('marry')
})

love.then(result => {
    console.log(result)
}).catch(result => {
    console.log(result)
})
複製代碼

2、Promise的then與catch的幾種寫法

第一種,最多見的就是上面的寫法, 使用then來捕捉resolve狀態,使用catch來捕捉reject狀態

love.then(result => {
    console.log(result)
}).catch(result => {
    console.log(result)
})

複製代碼

第二種,不寫catch, 把用來捕捉reject狀態的函數也寫到then裏,可是效果和上面同樣

love.then(result => {
    console.log(result)
}, result => {
    console.log(result)
})
複製代碼

第三種,分開寫,也是能夠的

love.then(result => {     //只捕捉和處理成功狀態
    console.log(result)
})

love.catch(result => {    //只捕捉和處理失敗狀態
    console.log(result)  
})
複製代碼

3、快速構建一個成功或是失敗狀態的Promise

Promise自帶了兩種方法,咱們能夠利用它們快速構建一個Promise,一個是Promise.resolve(), 用於構建成功狀態的Promise;另外一個是Promise.reject(),用於構建失敗狀態的Promise。app

let p1 = Promise.resolve('success')
console.log(p1)   // 打出來的是 Promise {'success'}
p1.then(result => {
    console.log(result)  //打出來上面resolve傳過來的字符串'success'
})

let p2 = Promise.reject('failed')   //上面是一個成功狀態Promise,這是一失敗狀態的Promise
p2.catch(result => {
    console.log(result)
})

複製代碼

4、使用Promise.all()來處理一類前端場景

在前端的開發實踐中,咱們有時會遇到須要發送多個請求並根據請求順序返回數據的需求,好比,咱們要發送a、b、c三個請求,這三個請求返回的數據分別爲a一、a二、a3,而咱們想要a一、a二、a3按照咱們但願的順序返回。那麼,使用Promise.all()方法能夠完美的解決這一問題。dom

假設使用代碼以下:異步

//模擬異步請求的函數
let request = (name, time) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            let random = Math.random()
            if (random >= 0.2) {
                resolve(`${name}成功了`)
            } else {
                reject(`${name}失敗了`)
            }
        }, time)    
    })
}

//構建三個Promise實例
let a = request('小明', 1000)
let b = request('小紅', 500)
let c = request('小華', 1500)

//使用Promise.all(), 注意它接收的是一個數組做爲參數 
Promise.all([b,a,c]).then(result => {
    console.log(result)
}).catch(result => {
    console.log(result)
})

複製代碼

把上面的代碼複製下來放到瀏覽器的調試控制檯裏多執行幾回(第二次執行須要刷新)會發生什麼事情呢?你可能猜到了:若是三個請求都成功的話,那麼這三個請求所返回的數據就是按照發送請求的順序排列的,即['小紅成功了', '小明成功了', '小華成功了'],並且仍是以數組形式返回的;而當其中有請求失敗了的話,就只會返回最早失敗的結果。async

固然,除了這個場景之外,Promise.all()方法還能用於其它地方。好比說,一個頁面上有兩個請求,只有拿到了這兩個請求的數據,頁面纔會展現,在這以前會顯示一個loading加載圖。使用Promise.all()也是能夠很是簡潔的解決這個問題。

5、Promise的鏈式調用

上面說過的then方法,在每次使用後依然會繼續返回一個Promise對象。

let p = Promise.resolve('success')
let response = p.then(result => {
    console.log(result)
})
console.log(response)   //打出來的response是一個Promise對象
複製代碼

由於then以後返回的仍是一個Promise對象,那咱們就能夠繼續then,只不事後面then拿到的參數是上一個then裏return的內容,而這個return的內容既能夠是普通的字符串、數字等(最後都會被封裝成Promise)也能夠是本身寫的一個Promise對象。

接下來咱們接着上面愛的承諾繼續寫一個鏈式調用的例子:

let love = new Promise((resolve, reject) => {
    setTimeout(() => {
        let happy = Math.random() >= 0.3 ? true : false
        if ( happy ) {
            resolve('marry')
        } else {
            reject('break')
        }    
    }, 500)
})

let haveChild = new Promise((resolve, reject) => {
    setTimeout(() => {
       resolve('孩子生了!') 
    }, 1000)
})


love.then(result => {
    console.log(result)
    return haveChild  // 這裏返回一個Promise對象,它的resolve會被下一個then捕捉
}).then(result => {
    console.log(result)
    return '最後,他們白頭偕老!' //這裏返回的字符串會傳給下一個then
}).then(result => {
    console.log(result)
}).catch(error => { 
    console.log(error)
})

複製代碼

這裏須要注意的是,在鏈式調用的最必定要加上一個catch來捕捉鏈條中可能出現的錯誤!

6、Promise鏈式調用能夠處理的一個業務場景

當咱們須要發送多個請求,然後一個請求老是依賴前一個請求的結果時,Promise的鏈式操做就能夠派上用場了。

咱們使用axios來演示,axios自己就使用Promise進行封裝,代碼以下:

let request = (url) => {
    let result = axios.get(url)  //result是Promise對象
    result.then(response => {
        return response
    }).catch(error => {
        throw new Error('出錯了!')
    })
}

request(url0).then(response => {
    return request(response.data.link)
}).then(result => {
    console.log(result)
}).catch(error => {
    console.log(error)
})

複製代碼

上面的代碼簡單模擬了一下這個過程,有些地方還不完善。

以上就是我對Promise用法的一點理解,不少地方還不完善,若是出錯,還請各位朋友們能及時指正!

這是我在掘金上的第一篇文章!感謝觀看!

相關文章
相關標籤/搜索