一個 Promise 就是一個表明了異步操做最終完成或者失敗的對象。這是MDN上關於Promise的解釋。在前端開發中,Promise常常被拿來用於處理異步和回調的問題,來規避回調地獄和更好排布異步相關的代碼。本篇文章對於Promise以及相關的async/await記錄一些本身的理解和體會。前端
從字面的意思理解,Promise便是承諾,既是承諾,那承諾的結果就會有成功和失敗兩種。並且,咱們許下承諾以後不會當即獲得結果,在得到成功或是失敗的結果以前,咱們還須要一點時間來履行這個承諾。Promise的構造其實像極了咱們生活中的承諾。ios
上面這張圖就是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)
})
複製代碼
love.then(result => {
console.log(result)
}).catch(result => {
console.log(result)
})
複製代碼
love.then(result => {
console.log(result)
}, result => {
console.log(result)
})
複製代碼
love.then(result => { //只捕捉和處理成功狀態
console.log(result)
})
love.catch(result => { //只捕捉和處理失敗狀態
console.log(result)
})
複製代碼
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)
})
複製代碼
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()
也是能夠很是簡潔的解決這個問題。
上面說過的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來捕捉鏈條中可能出現的錯誤!
當咱們須要發送多個請求,然後一個請求老是依賴前一個請求的結果時,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用法的一點理解,不少地方還不完善,若是出錯,還請各位朋友們能及時指正!
這是我在掘金上的第一篇文章!感謝觀看!