const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const PENDING = 'PENDING'
const resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
return reject(new TypeError('循环引用报错'))
}
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
let called;
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, y => {
if (called) return
called = true
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)
}
}
class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onfulfilledCallbacks = []
this.onrejectedCallbacks = []
let resolve = (value) => {
if (value instanceof Promise) {
return value.then(resolve, reject)
}
if (this.status === PENDING) {
this.value = value
this.status = RESOLVED
this.onfulfilledCallbacks.forEach(fn => fn())
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
this.onrejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onfulfilled, onrejected) {
onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : v => v;
onrejected = typeof onrejected === 'function' ? onrejected : err => {
throw err
};
let promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = onfulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onrejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === PENDING) {
this.onfulfilledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onfulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.onrejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onrejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
})
return promise2
}
catch (onrejected) {
return this.then(null, onrejected)
}
finally(cb) {
return this.then(
(data) => {
return Promise.resolve(cb()).then(() => data)
}, (err) => {
return Promise.resolve(cb()).then(() => { throw err })
})
}
static resolve(value) {
return new Promise((resolve, reject) => {
resolve(value)
})
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
static all(promises) {
return new Promise((resolve, reject) => {
let result = []
let times = 0
const processSuccess = (index, val) => {
result[index] = val
if (++times === promises.length) {
resolve(result)
}
}
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
if (p && typeof p.then === 'function') {
p.then(data => {
processSuccess(i, data)
}, reject)
} else {
processSuccess(i, p)
}
}
})
}
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
if (p && typeof p.then === 'function') {
p.then(data => {
resolve(data)
}, reject)
} else {
resolve(p)
}
}
})
}
}
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject
})
return dfd;
}
module.exports = Promise