promise使用及原理分析:
- 經過new關鍵字建立promise實例, 接受一個executor參數, executor方法返回兩個方法 resolve, reject, 可用經過在executor方法中經過調用resolve(使成功)或調用reject(使失敗),來控制promise狀態
let p = new Promise((resolve, reject) => {
resolve(100)
})
- executor中能夠執行同步代碼也能夠執行異步代碼
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(100)
})
})
- promise原型對象上有then方法供promise實例調用, then方法接受兩個參數onFulfilled, onRejected
- onFulfilled默認爲一個函數 data => data
- onRejected默認爲一個函數 err => {throw err}
- 當promise狀態爲fulfilled時, 執行用戶傳入的onFulfilled方法
- 當promise狀態爲rejected時, 執行用戶傳入的onRected方法
- 當用戶建立promise對象時採用異步,那麼執行then方法時沒有調用resolve方法或reject方法,因此promise狀態依然爲pending狀態,因此須要在then方法中採起發佈訂閱模式,先保存then方法傳來的onFulfilled和onReje
- 又由於同一個promise實例能夠調用屢次then方法,從而傳多個onFulfilled和onRected,因此發佈訂閱採用數組保存
- onFulfilled和onRejected方法中可能throw Error, 因此在執行onFulfilled和onRejected時須要try catch捕獲
- then方法返回一個新的Promise實現鏈式編程
- 統一判斷then方法傳入的onFulfilled方法和onRejected方法中return的類型(resolvePromise)
p.then(data => {
console.log(data)
}, err => {
console.log(err)
})
let p1 = p.then(data => {
return p1 // 報類型錯誤
})
p.then(data => {
return new Promise((resolve, reject) => {
resolve(100)
})
})
- catch方法接受一個錯誤回調,能夠用then方法實現(語法糖)
- ES2018 中新增finally方法 也能夠經過then方法實現(語法糖) finally要實現值得穿透, finally前若是有then方法,其返回值要穿過finally方法傳給以後的then
p.then(data => {
return 100
}).finally(() => {
console.log('finally')
}).then(data => {
console.log(data) // 100
})
- all, race 方法都接受一個promise數組
- all方法要全部promise都返回才resolve一個所有是成功態的數組,只要有一個rejected就直接reject
- race方法只要有一個promise resolve就直接resolve
完整代碼以下:
class Promise {
constructor(executor) {
this.status = Promise.PENDING
this.value = undefined
this.reason = undefined
// 發佈訂閱的存儲器onResolvedCallbacks, onRejectedCallbacks
this.onResolvedCallbacks = []
this.onRejectedCallbacks = []
this.initBind()
this.init(executor)
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
init(executor) {
// 防止executor中拋錯
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve(data) {
// 若是resolve中傳入一個promise, 那麼返回改promise結果
if (data instanceof Promise) data.then(this.resolve, this.reject)
if (this.status === Promise.PENDING) {
this.status = Promise.FULFILLED
this.value = data
this.onResolvedCallbacks.forEach(fn => fn())
}
}
reject(reason) {
if (this.status === Promise.PENDING) {
this.status = Promise.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
}
then(onFulfilled, onRejected) {
const fulfilledHandle = (resolve, reject) => {
// 此處用setTimeout異步才能拿到promise2
setTimeout(() => {
try {
let x = onFulfilled(this.value)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
const rejectHandle = (resolve, reject) => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
// onFulfilled和onRejected定義默認值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
}
let promise2 = new Promise((resolve, reject) => {
if (this.status === Promise.FULFILLED) {
fulfilledHandle(resolve, reject)
}
if (this.status === Promise.REJECTED) {
rejectHandle(resolve, reject)
}
if (this.status === Promise.PENDING) {
this.onResolvedCallbacks.push(() => {
fulfilledHandle(resolve, reject)
})
this.onRejectedCallbacks.push(() => {
rejectHandle(resolve, reject)
})
}
})
// 返回一個新的promise
return promise2
}
catch (onRejected) {
return this.then(null, onRejected)
}
static resolve() {
return new Promise((resolve, reject) => {
resolve()
})
}
static reject() {
return new Promise((resolve, reject) => {
reject()
})
}
finally(callback) {
return this.then(
data => Promise.resolve(callback()).then(() => data),
err => Promise.resolve(callback()).then(() => {
throw err
})
)
}
static all(promises) {
return new Promise((resolve, reject) => {
let result = []
let count = 0
const setResult = (key, value) => {
result[key] = value
if (++count === promises.length) {
resolve(result)
}
}
for (let i = 0; i < promises.length; i++) {
let current = promises[i]
if (Promise.isPromise(current)) {
current.then(data => {
setResult(i, data)
}, reject)
} else {
setResult(i, current)
}
}
})
}
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
let current = promises[i]
if (Promise.isPromise(current)) {
current.then(resolve, reject)
} else {
resolve(current)
}
}
})
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
Promise.resolvePromise = (promise2, x, resolve, reject) => {
// called防止他人的promise即執行resolve又執行 reject
let called
if (promise2 === x) throw new TypeError('xxx')
if (typeof x === 'function' || typeof x === 'object' && x !== null) {
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, y => {
if (called) return
called = true
// 遞歸解析,總有一個結果then方法返回一個普通值
Promise.resolvePromise(promise2, y, resolve, reject)
}, e => {
if (called) return
called = true
reject(e)
})
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
Promise.isPromise = (obj) => {
return typeof obj === 'function' || typeof obj === 'object' && obj !== null && obj.then && typeof obj.then === 'function'
}
// 延遲對象
Promise.deferred = () => {
const defer = {}
defer.promise = new Promise((resolve, reject) => {
defer.resolve = resolve
defer.reject = reject
})
return defer
}
module.exports = Promise