const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING // 当前状态
this.value = null // 成功的值
this.reason = null // 失败的值
this.onFulfilledCallbacks = [] //成功回调
this.onRejectedCallbacks = [] // 失败回调
// resolve和reject为什么要用箭头函数?
// 如果直接调用的话,普通函数this指向的是window或者undefined
// 用箭头函数就可以让this指向当前实例对象
const resolve = (value) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
this.status = FULFILLED // 更改状态
this.value = value // 成功赋值
// resolve里面将所有成功的回调拿出来执行
this.onFulfilledCallbacks.forEach((fn) => fn(value))
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED // 更改状态
this.reason = reason // 失败赋值
// resolve里面将所有失败的回调拿出来执行
this.onRejectedCallbacks.forEach((fn) => fn(reason))
}
}
try {
// 执行
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
// 保证onFulfilled 和onRejected为一个函数
const realOnfulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value
const realonRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
// 链式调用,直接return出去promise2
const promise2 = new MyPromise((resolve, reject) => {
// 成功的微任务
const fulfilledMicrotask = () => {
// 创建一个微任务等待promise2完成初始化
queueMicrotask(() => {
try {
// 获取成功的结果
const x = realOnfulfilled(this.value)
// 传入resolvePromise集中处理
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
// 失败的微任务
const rejectMicrotask = () => {
// 创建一个微任务等待promise2完成初始化
queueMicrotask(() => {
try {
// 获取失败的结果
const x = realonRejected(this.reason)
// 传入resolvePromise集中处理
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
// 当前状态做判断
if (this.status === FULFILLED) {
fulfilledMicrotask()
} else if (this.status === REJECTED) {
rejectMicrotask()
} else if (this.status === PENDING) {
// 等待
// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
// 等到执行成功失败函数的时候再传递
this.onFulfilledCallbacks.push(fulfilledMicrotask)
this.onRejectedCallbacks.push(rejectMicrotask)
}
})
return promise2
}
// 失败的错误捕获
// Promise.prototype.catch()方法是.then(null, rejection)
// 或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数
catch(onRejected) {
this.then(undefined, onRejected)
}
// finally()方法用于指定不管 Promise 对象最后状态如何,
// 都会执行的操作。该方法是 ES2018 引入标准的。
finally(fn) {
return this.then(
(value) => {
return MyPromise.resolve(fn()).then(() => {
return value
})
},
(reason) => {
return MyPromise.resolve(fn()).then(() => {
throw reason
})
}
)
}
// resolve 静态方法 通过 MyPromise.resolve()调用
static resolve(parmeter) {
// 如果传入 MyPromise 就直接返回
if (parmeter instanceof MyPromise) {
return parmeter
}
return new MyPromise((resolve) => {
resolve(parmeter)
})
}
// reject 静态方法 通过 MyPromise.reject()调用
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
// all的静态方法 通过 MyPromise.all()调用
// 只要参数实例有一个变成rejected状态,包装实例就会变成rejected状态;
// 如果所有参数实例都变成fulfilled状态,包装实例就会变成fulfilled状态。
static all(promiseList) {
return new MyPromise((resolve, reject) => {
const result = []
const length = promiseList.length
let count = 0
if (length === 0) {
return resolve(result)
}
promiseList.forEach((promise, index) => {
// 保证是一个promise
MyPromise.resolve(promise).then(
(value) => {
count++
result[index] = value
if (count === length) {
resolve(result)
}
},
(reason) => {
reject(reason)
}
)
})
})
}
// any 的静态方法 通过 MyPromise.any()调用 es2021加入 和all刚好相反
// 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;
// 如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
static any(promiseList) {
return new MyPromise((resolve, reject) => {
let count = 0
let result = []
let len = promiseList.length
if (len === 0) return resolve(result)
promiseList.forEach((item) => {
// 保证是一个promise
MyPromise.resolve(item).then(
(value) => {
resolve(value)
},
(reason) => {
count++
result.push(reason)
if (count === len) {
reject(result)
}
}
)
})
})
}
// allSettled 的静态方法 通过 MyPromise.allSettled()调用
// ES2020 引入了Promise.allSettled()方法 用来确定一组异步操作是否都结束了(不管成功或失败)
//返回格式: [
// { status: 'fulfilled', value: value},
// { status: 'rejected', reason: reason }
// ]
static allSettled(promiseList) {
return new MyPromise((resolve) => {
const length = promiseList.length
const result = []
let count = 0
if (length === 0) {
return resolve(result)
} else {
for (let i = 0; i < length; i++) {
const currentPromise = MyPromise.resolve(promiseList[i])
currentPromise.then(
(value) => {
count++
result[i] = {
status: 'fulfilled',
value: value,
}
if (count === length) {
return resolve(result)
}
},
(reason) => {
count++
result[i] = {
status: 'rejected',
reason: reason,
}
if (count === length) {
return resolve(result)
}
}
)
}
}
})
}
// race 的静态方法 通过 MyPromise.race()调用
// 只要有个实例决议后就返回改该决议后的结果
static race(promiseList) {
return new MyPromise((resolve, reject) => {
const length = promiseList.length
if (length === 0) {
return resolve()
} else {
for (let i = 0; i < length; i++) {
MyPromise.resolve(promiseList[i]).then(
(value) => {
return resolve(value)
},
(reason) => {
return reject(reason)
}
)
}
}
})
}
}
function resolvePromise(promise, x, resolve, reject) {
if (promise === x) {
return reject(new TypeError('cycle....'))
}
if ((typeof x === 'object' || typeof x === 'function') && x !== null) {
let then
try {
then = x.then
} catch (error) {
return reject(error)
}
if (typeof then === 'function') {
let called = false
try {
then.call(
x,
(y) => {
if (called) return
called = true
resolvePromise(promise, y, resolve, reject)
},
(r) => {
if (called) return
called = true
reject(r)
}
)
} catch (error) {
if (called) return
reject(error)
}
} else {
resolve(x)
}
} else {
resolve(x)
}
}
MyPromise.deferred = function () {
var result = {}
result.promise = new MyPromise(function (resolve, reject) {
result.resolve = resolve
result.reject = reject
})
return result
}
// 值穿透
MyPromise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
MyPromise.resolve(1)
.then(() => { return 2 })
.then(() => { return 3 })
.then(console.log)
MyPromise.resolve(1)
.then(function () {
return 2
})
.then(() => { Promise.resolve(3) })
.then(console.log)
MyPromise.reject(1)
.then(res => {
console.log(res);
})
.then(res => { console.log(res) },
rej => {
console.log(`rej****${rej}`);
})
.catch(err => {
console.log(`err****${err}`);
})
const resolved = MyPromise.resolve(42);
const rejected = MyPromise.reject(-1);
const allSettledPromise = MyPromise.allSettled([resolved, rejected]);
allSettledPromise.then(function (results) {
console.log(results);
});
module.exports = MyPromise