const FULFILLED = "fulfilled"
const REJECTED = "rejected"
const PENDING = "pending"
function Promise(executor) {
let self = this
self.status = PENDING
self.value = undefined
self.reason = undefined
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
// setTimeout 原因 :
// 规范规定 onFulfilled 和 onRejected 不能被调用
// 直到执行栈只包含平台代码
// 平台代码指 引擎, 环境, promise 实现代码
function resolve(value) {
setTimeout(() => {
self.status = FULFILLED
self.value = value
self.onFulfilledCallbacks.forEach(cb => cb(value))
})
}
function reject(reason) {
setTimeout(() => {
self.status = REJECTED
self.reason = reason
self.onRejectedCallbacks.forEach(cb => cb(reason))
})
}
try {
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this, promise2
// 三元表达式解决值穿透的问题
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value
onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason
if (self.status === FULFILLED) {
return promise2 = new Promise((res, rej) => {
setTimeout(() => {
try {
let x = onFulfilled(self.value)
__resolve__(promise2, x, res, rej)
} catch (e) {
rej(e)
}
})
})
}
if (self.status === REJECTED) {
return promise2 = new Promise((res, rej) => {
setTimeout(() => {
try {
let x = onRejected(self.reason)
__resolve__(promise2, x, res, rej)
} catch (e) {
rej(e)
}
})
})
}
if (self.status === PENDING) {
return promise2 = new Promise((res, rej) => {
self.onFulfilledCallbacks.push(value => {
try {
let x = onFulfilled(value)
__resolve__(promise2, x, res, rej)
} catch (e) {
rej(e)
}
})
self.onRejectedCallbacks.push(reason => {
try {
let x = onRejected(reason)
__resolve__(promise2, ex, res, rej)
} catch (e) {
rej(e)
}
})
})
}
}
function __resolve__(promise2, x, res, rej) {
if (promise2 === x) throw TypeError("循环引用")
let called = false
if (x !== null && (typeof x === "object" || typeof x === "function")) {
try {
let then = x.then
if (typeof then === "function") {
then.call(x, y => {
if (called) return
called = true
__resolve__(promise2, y, res, rej)
}, reason => {
if (called) return
called = true
rej(reason)
})
}
else res(x)
} catch (e) {
rej(e)
}
}
else res(x)
}
Promise.prototype.catch = function(onRejected) {
return this.then(undefined, onRejected)
}
Promise.all = function (promises) {
let rejected = false, cnt = promises.length, values = []
return new Promise((res, rej) => {
promises.forEach(p => {
p.then(value => {
if (rejected) return
values.push(value)
if (--cnt === 0) res(values)
}, reason => {
if (rejected) return
rejected = true
rej(reason)
})
})
})
}
Promise.resolve = function(value) {
return new MyPromise(res => res(value))
}
Promise.reject = function(reason) {
return new MyPromise((res, rej) => rej(reason))
}