const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor){
let self = this
self.state = PENDING
self.value = null
self.reason = null
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
function resolve(value) {
if(self.state === PENDING) {
self.state = FULFILLED
self.value = value
self.onFulfilledCallbacks.forEach(fulfilledCallback => fulfilledCallback())
}
}
function reject(reason) {
if(self.state === PENDING) {
self.state = REJECTED
self.reason = reason
self.onRejectedCallbacks.forEach(rejectedCallback => rejectedCallback())
}
}
try {
executor(resolve, reject)
} catch (reason) {
reject(reason)
}
}
Promise.prototype.then = function(onFulfilled, onRejected) {
let self = this
let promise2 = null
promise2 = new Promise((resolve, reject)=>{
if(self.state === PENDING) {
self.onFulfilledCallbacks.push(()=>{
setTimeout(function(){
try {
let x = onFulfilled(self.value)
self.resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
}, 0)
})
self.onRejectedCallbacks.push(()=>{
setTimeout(function(){
try {
let x = onRejected(self.reason)
self.resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
}, 0)
})
}
if(self.state === FULFILLED) {
setTimeout(function(){
try {
let x = onFulfilled(self.value)
self.resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
}, 0)
}
if(self.state === REJECTED) {
setTimeout(function(){
try {
let x = onRejected(self.reason)
self.resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
}, 0)
}
})
return promise2
}
Promise.prototype.resolvePromise = function(promise2, x, resolve, reject) {
let self = this
let called= false
if(promise2 === x) {
return reject(new TypeError('循环引用'))
}
if(x !== null && (Object.prototype.toString.call(x)==='[object Object]'||Object.prototype.toString.call(x)==='[object Function]')){
try {
let then = x.then
if(typeof then === 'function') {
then.call(x, y=>{
if(called) return
called = true
self.resolvePromise(promise2, y, resolve, reject)
}, reason=>{
if(called) return
called = true
reject(reason)
})
} else {
resolve(x)
}
} catch (reason) {
if(called) return
called = true
reject(reason)
}
} else {
resolve(x)
}
}
module.exports = Promise