手写Promise
整体架构
![(img-2ygDM59G-1591101279398)(Promise.assets/image-20200504083131613.png)]](https://i-blog.csdnimg.cn/blog_migrate/0afba2b32a4a0f8f334d293780e5399b.png#pic_center)
Es5的写法
~(function (window) {
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function Promise(executor) {
this.state = PENDING
this.data = null
this.callbacks = []
function resolve(value) {
if (this.state !== PENDING) {
return
}
this.state = RESOLVED
this.data = value
if (this.callbacks.length > 0) {
setTimeout(() => {
this.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value)
})
})
}
}
function reject(reason) {
if (this.state !== PENDING) {
return
}
this.state = REJECTED
this.data = reason
if (this.callbacks.length > 0) {
setTimeout(() => {
this.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason)
})
})
}
}
try {
executor(resolve.bind(this), reject.bind(this))
} catch (e) {
reject(e)
}
}
Promise.prototype = {
constructor: Promise,
then(onResolved, onRejected) {
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
}
onResolved = typeof onResolved === 'function' ? onResolved : value => value
const self = this
return new Promise((resolve, reject) => {
function handle(callback) {
try {
const result = callback(self.data)
if (result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (e) {
reject(e)
}
}
if (self.state === PENDING) {
self.callbacks.push({
onResolved() {
handle(onResolved)
},
onRejected() {
handle(onRejected)
}
})
} else if (self.state === RESOLVED) {
setTimeout(() => {
handle(onResolved)
})
} else {
setTimeout(() => {
handle(onRejected)
})
}
})
},
catch (onRejected) {
return this.then(null, onRejected)
}
}
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
Promise.all = function (iterable) {
return new Promise((resolve, reject) => {
const arr = new Array(iterable.length)
const counter = 0
iterable.forEach((p, index) => {
Promise.resolve(p).then(
value => {
arr[index] = value
counter++
counter === arr.length ? resolve(arr) : null
},
reason => {
reject(reason)
}
)
})
})
}
Promise.all(iterable) {
return new Promise((resolve, reject) => {
let arr = []
iterable.forEach((p, index) => {
Promise.resolve(p).then(
value => {
arr[index] = value
if(arr.length === iterable.length) {
resolve(arr)
}
} ,
reason => {
reject(reason)
}
)
})
})
}
Promise.race = function (iterable) {
return new Promise((resolve, reject) => {
iterable.forEach(p => {
Promise.resolve(p).then(
value => {
resolve(value)
},
reason => {
reject(reason)
}
)
})
})
}
Promise.resolveDelay = function(value, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
}, time)
})
}
Promise.rejectDelay = function(reason, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(reason)
}, time)
})
}
window.Promise = Promise
})(window)
Class写法
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class Promise {
constructor(executor) {
this.state = PENDING
this.data = null;
this.callbacks = []
let resolve = value => {
if(this.state !== PENDING) {
return
}
this.state = RESOLVED
this.data = value
if(this.callbacks.length) {
process.nextTick(() => {
this.callbacks.forEach(item => {
item.onResolved(this.data)
})
})
}
}
let reject = reason => {
if(this.state !== PENDING) {
return
}
this.state = REJECTED
this.data = reason
if(this.callbacks.length) {
process.nextTick(() => {
this.callbacks.forEach(item => {
item.onRejected(this.data)
})
})
}
}
try {
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
then(onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
return new Promise((resolve, reject) => {
let handle = callback => {
try {
const result = callback(this.data)
if(result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch(e) {
reject(e)
}
}
if(this.state === PENDING) {
this.callbacks.push({
onResolved() {
handle(onResolved)
},
onRejected() {
handle(onRejected)
}
})
} else if(this.state === RESOLVED) {
process.nextTick(() => {
handle(onResolved)
})
} else {
process.nextTick(() => {
handle(onRejected)
})
}
})
}
catch(onRejected) {
return this.then(null, onRejected)
}
static resolve(value) {
return new Promise((resolve, reject) => {
if(value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
static reject(reason) {
return new Promise((resolve, reject) => {
if(reason instanceof Promise) {
reason.then(reject, reject)
} else {
reject(reason)
}
})
}
static all(iterable) {
return new Promise((resolve, reject) => {
const arr = []
let counter = 0
iterable.forEach((p, index) => {
Promise.resolve(p).then(
value => {
counter++
arr[index] = value
if(counter === iterable.length) {
resolve(arr)
}
},
reason => {
reject(reason)
}
)
})
})
}
}
module.exports = Promise