在做中學的過程中,遇到 Promise 物件總是 then 來 then 去,雖然大致了解作法及應用方式,但是一直沒有時間停下腳步仔細看看,內心覺得有點不踏實;因此最近花了一點時間看看文章,寫了一下筆記希望能幫助到需要的人。
前言
當今作為 Http Client 套件 ( jQuery, axios, fetch ... ) 多數已支援 Promise 標準,開發人員可透過 Promise 物件掌控非同步作業的執行狀態,依據 Promise 狀態決定成功 / 失敗時所需執行的行為,在語法使用上較傳統 call back 方式清晰好理解。本篇文章針對 Promise 物件的操作方式進行介紹,對 Promise 有初步的認識後,在操作上比較不會迷失在 then 來 then 去的 promise chain 中。
建立 Promise 物件
建立 Promise 方式如下
var promise = new Promise ( (resolve, reject) => { ... } )
- 在建構函式傳入 executor 函式
- 可在函式中執行非同步作業
- 當作業順利完成後:
- 呼叫 resolve(value) 回應所得資料
- value 通常是合法的 javascript 值
- 會進入 Fulfilled (已實現) 狀態
- 當作業發生錯誤時:
- 呼叫 reject(reason) 回應錯誤資訊
- reason 通常會式 Error 物件
- 會進入 Rejected (已拒絕) 狀態
範例如下:
function doSomethingAsync(){
return new Promise((resolve, reject) => {
// 模擬非同步作業(ex. call api)
setTimeout(function () {
let isSuccess = false
if (isSuccess) {
// 成功(資料 value 向下一個連鎖傳遞)
resolve('success')
} else {
// 失敗(錯誤 reason 向下一個連鎖傳遞)
reject(new Error('something wrong'))
}
}, 2000)
})
}
依據 promise 狀態來決定處置方式
可使用 then 獲得最終處理結果及進行接續行為
var newPromise = promise.then( onFulfilled, onRejected )
- 傳入 onFulfilled 方法來定義作業成功時的處理方式
- 傳入 onRejected 方法來定義作業失敗時的處理方式
- 執行後會另外產生新的 Promise 物件
(因此可以使用 chained 結構繼續操作 promise)
onFulfilled = (value) => {...}
- 在 Promise 的 executor 中呼叫 resolve 方法會進入此方法中
( 狀態為 Fulfilled 已實現時 ) - 傳入值:
- 由上層 executor 透過 resolved(value) 傳入的資料
- 或從上層 onFulfilled 或 onRejected 方法直接 return value
- 不區分值是從 onFulfilled 還是 onRejected 傳出來 (因在 onFulfilled 或 onRejected 不發生錯誤 / 不呼叫 reject 時,都會進入下個 onFulfilled 中,當然也包括回傳值)
- 回傳值:
- value 值 (可以從新Promise 物件 then 中 onFulfilled 方法參數中取得)
- Promise 物件
- 當有需要再處理一個非同步作業時使用
- 自己建立一個 Promise 取代 then 回傳的新 Promise 物件
- thenable 物件
onRejected = (reason) => {...}
- 在 Promise 的 executor 中呼叫 reject方法會進入此方法中
( 狀態為 Rejected 已拒絕時 ) - 傳入值:
- 由上層 executor 透過 reject(reason) 傳入的錯誤發生資訊
- 或從上層 onFulfilled 或 onRejected 方法直接呼叫 Promise.reject(reason)
- 回傳值:也是可以回傳 value, promise 或 thenable 物件
- 多數使用情境下在 then 中只會定義 onFulfilled 方法 (會忽略此部分)
- 錯誤多會交由 promse.catch 作攔截處置
範例如下:
// promise 成功要執行的方法
function onFulfilled (value) {
console.log(value) // 'success'
}
// promise 失敗要執行的方法
function onRejected (reason) {
console.log(reason.message) // 'something wrong'
}
// then 就是處置 promise 成功或失敗要做的事情
doSomethingAsync()
.then(onFulfilled, onRejected)
// 通常不特別在 then 中定義 onRejected 方法
// 多數使用 catch 直接捕捉/處理上方連鎖發生的錯誤
doSomethingAsync()
.then(onFulfilled)
.catch(onRejected) // 等同 then(undefined, onRejected)
執行等待多個 promise 皆處理完畢 ( 靜態方法 all )
使用 all 執行陣列中的所有 promise 物件
Promise.all( [promise1, promise2 ....] ).then( onFulfilled ). catch( onReject )
- 所有 promise 都 resolve 後才會進入 onFulfilled
(onFulfilled 中傳入的 value 為陣列格式,保存各 promise 回傳的值) - 陣列順序與執行順序無關
- 所有 promise 其中任一發生錯誤或 reject 情況則馬上回傳
範例如下:
var promise1 = new Promise((resolve)=>{
setTimeout(()=>{
resolve('take 1 second')
},1000)
})
var promise2 = new Promise((resolve)=>{
setTimeout(()=>{
resolve('take 2 second')
},2000)
})
Promise.all([promise1, promise2])
.then((values)=>{
console.log(values) // ['take 1 second', 'take 2 second']
})
.catch((error)=>{
console.log(error)
})
建立已具狀態的 promise 物件 ( 靜態方法 resolve 與 reject )
直接產生 Fulfilled 已實現狀態的 promise 物件 ( 只會進入 onFulfilled )
Promise.resolve( value ).then(onFulfilled, onRejected)
直接產生 Rejected 已拒絕狀態的 promise 物件 ( 只會進入 onRejected )
Promise.reject( reason ).then(onFulfilled, onRejected)
// promise 成功要執行的方法
function onFulfilled (value) {
console.log(value)
}
// promise 失敗要執行的方法
function onRejected (reason) {
console.log(reason.message)
}
Promise.resolve('success').then(onFulfilled, onRejected)
// go onFulfilled and show "success"
Promise.reject(new Error('fail')).then(onFulfilled, onRejected)
// go onRejected and show "fail"
參考資訊
希望此篇文章可以幫助到需要的人
若內容有誤或有其他建議請不吝留言給筆者喔 !