Promise原理手写实现
已实现方法
- p.then()
- p.catch()
- Promise.all()
- Promise.race()
代码演示
Talk is cheap, show me the code!
new Promise()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| function MyPromise(executor) { this.status = 'pending' this.resolvedValue = null this.rejectedValue = null this.onFullFilledList = [] this.onRejectedList = []
const _this = this
function resolve(value) { if (_this.status === 'pending') { _this.status = 'fulfilled' _this.resolvedValue = value
_this.onFullFilledList.forEach((fn) => fn(value)) } }
function reject(value) { if (_this.status === 'pending') { _this.status = 'reject' _this.rejectedValue = value
_this.onRejectedList.forEach((fn) => fn(value)) } }
try { executor(resolve, reject) } catch (err) { console.log(err) } }
|
.then()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| MyPromise.prototype.then = function (onFulfilled, onRejected) { if (!isFunction(onFulfilled)) onFulfilled = (value) => value if (!isFunction(onRejected)) onRejected = (reason) => throw reason
const taskOfFulfilled = () => { queueMicrotask(() => { try { const prevResult = onFulfilled(this.resolvedValue) handlePromise(promise2, prevResult, resolve, reject) } catch (err) { reject(err) } }) }
const taskOfRejected = () => { queueMicrotask(() => { try { const prevResult = onRejected(this.rejectedValue) handlePromise(promise2, prevResult, resolve, reject) } catch (err) { reject(err) } }) }
const promise2 = new MyPromise((resolve, reject) => { if (this.status === 'fulfilled') {
taskOfFulfilled() }
if (this.status === 'reject') taskOfRejected()
if (this.status === 'pending') { this.onFullFilledList.push(taskOfFulfilled) this.onRejectedList.push(taskOfRejected) } })
return promise2 }
|
handlePromise()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| function handlePromise(promise2, prevResult, resolve, reject) { if (promise2 === prevResult) { return reject( new TypeError('Chaining cycle detected for promise #<Promise>') ) }
if (typeof prevResult === 'object' && prevResult !== null) { let then = prevResult?.then try { if (typeof then === 'function') { let called = false then.call( prevResult, (res) => { if (called) return called = true handlePromise(promise2, res, resolve, reject) }, (err) => { if (called) return called = true reject(err) } ) } else { resolve(prevResult) } } catch (err) { if (called) return called = true reject(err) } } else { resolve(prevResult) } }
|
.catch()
1 2 3
| MyPromise.prototype.catch = function (onRejected) { return this.then(undefined, onRejected) }
|
Promise.all()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
MyPromise.all = function (promises) { return new MyPromise((resolve, reject) => { if (!promises || !Array.isArray(promises)) return reject() const len = promises.length const result = []
const process = (data) => { result.push(data) if (len === result.length) resolve(result) }
for (const promise of promises) { if (isPromise(promise)) { promise.then( (data) => { process(data) }, (err) => { return reject(err) } ) } else { process(promise) } } }) }
|
Promise.race()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
MyPromise.race = function (promises) { return new MyPromise((resolve, reject) => { if (!promises || !Array.isArray(promises)) return reject()
for (const promise of promises) { if (isPromise(promise)) { promise.then( (data) => { resolve(data) return }, (err) => { reject(err) return } ) } else { resolve(promise) } } }) }
|
Utils-工具函数
isFunction()
1 2 3
| function isFunction(o) { return typeof o === 'function' }
|
isPromise()
1 2 3 4 5 6 7
| function isPromise(promise) { return ( typeof promise === 'object' && promise !== null && typeof promise.then === 'function' ) }
|
Test Cases
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| const p = new MyPromise((resolve, reject) => { setTimeout(() => { resolve(100) }, 2000)
})
|
总结