感性上的理解:Promise
咱們能夠理解爲作了一個保證,作了這個保證無論成功resolve()
仍是失敗reject()
都會告知咱們———返回帶有最終結果或者拒絕緣由 的Promise
。javascript
其中後兩種都是異步操做完成後的狀態java
Promise
對象用於表示一個異步操做的最終狀態(完成或失敗),以及其返回的值。ios
MDN對Promise的定義如上,能夠理解爲此對象作了一些保證,告知咱們異步操做的狀態。具體以下:axios
存在的需求:有時候咱們須要連續調用多個異步操做,每個操做都創建在獲得上一部結果以後。之前有回調函數,這樣會容易形成回調地獄。而採用Promise以後,每一步操做成功/失敗以後都會帶上其結果,執行下一個操做。api
// 回調地獄
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
//採用Promise鏈式調用以後
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
複製代碼
在上面的代碼段1中,有三個錯誤回調函數。而在Promise鏈式調用中,只在結尾加上錯誤處理回調便可,當有錯誤拋出時,會返回一個帶有錯誤緣由的Promise到下一級catch,直到最底端catch函數。數組
// 依次輸出: Initial Do that
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
throw new Error('Something failed');
console.log('Do this');
})
.then(() => {
console.log('Do this whatever happened before');
})
.catch(() => {
console.log('Do that');
})
複製代碼
此外,若是中途捕獲了異常,依然能夠接着then下去:promise
/* * 依次輸出: * Initial * Do that * Do this whatever happened before */
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
throw new Error('Something failed');
console.log('Do this');
})
.catch(() => {
console.log('Do that');
})
.then(() => {
console.log('Do this whatever happened before');
})
複製代碼
緣由在於catch(failureCallback)
自己是then(null, failureCallback)
的縮略形式,也是返回帶有當前狀態的Promise。下面這樣我們還能捕獲到異常信息:app
/* * 依次輸出: * Initial * Something failed * Do that * Do this whatever happened before */
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
throw new Error('Something failed');
console.log('Do this');
})
.catch((e) => {
console.log(e.message)
console.log('Do that');
})
.then(() => {
console.log('Do this whatever happened before');
})
複製代碼
一個栗子異步
// 使用Promise
doSth()
.then(res => doSthElse(res))
.then(newRes => doThirdTh(newRes))
.then(finalRes => {
console.log(`finalResult is ${finalRes}`)
})
// 使用async/await將異步代碼寫成同步樣式
async funtion foo () {
let res = await doSth()
let newRes = await doSthElse(res)
let finalRes = await doThirdTh(newRes)
console.log(`finalResult is ${finalRes}`)
}
複製代碼
使用這兩種靜態方法能夠建立resolve或reject的保證,栗子以下:async
getRecommend () {
let today = new Date()
let date = new Date(today.getFullYear(), today.getMonth() + 1, today.getDate(), 9)
return axios.get(`/api/getRecommend?date=${Number(date)}`
).then(response => {
return Promise.resolve(response.data)
}).catch(err => {
console.log(err)
})
}
複製代碼
當使用axios
成功請求/api/getRecommend
時,axios返回一個Promise對象,由於getRecommend()
是要export出去的,這裏直接返回一個狀態完成的Promise,調用getRecommend()
時,若是成功響應直接能夠recommend.getRecommend().then(res => {})
獲取響應結果。
Promise.all()
是全部Promise對象狀態都是‘已成功’才結束Promise.race()
是有一個Promise對象狀態‘已成功’就結束下面這個累加例子很好地顯示了Promise之間傳值計算:
// 第一步,執行XXX操做,保證了***結果
let step1 = function () {
let val = 1
console.log(`this is step1 , the value is ${val}`)
// 拒絕的狀況,balalala...
if (val > 0){
return Promise.resolve(val)
}
return Promise.reject(val)
}
// 第二步,執行XXX操做,保證了***結果
let step2 = function (val) {
val += 1
console.log(`this is step2 , the value is ${val}`)
return Promise.resolve(val)
}
// 第三步,執行XXX操做,保證了***結果
let step3 = function (val) {
val += 1
console.log(`this is step3 , the value is ${val}`)
return Promise.resolve(val)
}
step1().then((val)=>{
return step2(val)
}).then((val)=>{
return step3(val)
}).then((val)=>{
console.log(`finally, the value is ${val}`)
})
// 輸出結果
this is step1 , the value is 1
this is step2 , the value is 2
this is step3 , the value is 3
複製代碼
再用async/await
語法糖實現一遍累加
// 在這裏咱們把每一步操做看做異步的
function step21() {
let val = 1
console.log(`this is step1 , the value is ${val}`)
return val
}
function step22(val) {
val += 1
console.log(`this is step2 , the value is ${val}`)
return val
}
function step23(val) {
val += 1
console.log(`this is step3 , the value is ${val}`)
return val
}
(async () => {
// await使用必須在async函數內
let val = await step21()
val = await step22(val)
val = await step23(val)
})()
// 輸出結果
this is step1 , the value is 1
this is step2 , the value is 2
this is step3 , the value is 3
複製代碼
使用數組的reduce()
方法依次執行,
// 第一步,執行XXX操做,保證了***結果
let step1 = function () {
let val = 1
console.log(`this is step1 , the value is ${val}`)
// 拒絕的狀況,balalala...
if (val > 0){
return Promise.resolve(val)
}
return Promise.reject(val)
}
// 第二步,執行XXX操做,保證了***結果
let step2 = function (val) {
val += 1
console.log(`this is step2 , the value is ${val}`)
return Promise.resolve(val)
}
// 第三步,執行XXX操做,保證了***結果
let step3 = function (val) {
val += 1
console.log(`this is step3 , the value is ${val}`)
return Promise.resolve(val)
}
let steps = [step1, step2, step3]
steps.reduce((promise, fn, index)=>{
console.log(index)
return promise.then((val)=>{
return fn(val)
})
// reduce函數init參數
}, Promise.resolve())
// 輸出結果
this is step1 , the value is 1
this is step2 , the value is 2
this is step3 , the value is 3
複製代碼
暫時只想到數組的方法,使用Array.prptotype.reduce()
爲解決,仍是沒有深刻了解reduce()
是如何實現的
async function foo () {
let val
for (let i = 0; i < steps.length; i++) {
if (i===0) {
val = await steps[i]()
}else {
val = await steps[i](val)
}
}
}
foo()
複製代碼