首先回顾一下原生Promise的使用:
const promise = new Promise((resolve, reject)=>{
resolve(true)
})
promise.then(
(result)=>{
console.log(result) // true
},
(reason)=>{
console.log(reason)
})
通过Promise构造函数new了一个实例,传入一个函数 函数入参为成功和失败的两个函数resolve和reject分别传入Promise成功的值和失败的拒因(失败的字符串或error对象) 等resolve/reject执行后拿到结果,执行promise.then传入的成功/失败的回调 所以promise.catch===promise.then(null,(reason)=>{})
对于then传入的第二个函数可能会有疑惑,其实then有两个参数,第一个是resolve成功的回调,第二个是reject失败的回调 实际开发只用第一个不建议写第二个参数 也是推荐的写法 reject回调推荐再.catch一下
再看下PromiseA+规范术语:
我们要写的MyPromise是一个构造函数/类,实例化时传入一个函数,函数里resolve和reject函数,然后类里有一个then方法,写一个promise初始雏形:
function MyPromise(executor) {
// 定义promise成功的resolve方法
function resolve(result) {}
// 定义promise失败的reject方法
function reject(reason) {}
// then方法
this.then = function (onFulfilled, onRejected) {}
// executor是个函数 执行创建promise时new Promise(executor)传入的executor 将onFulfilled方法和onRejected方法传入
executor && executor(resolve.bind(this), reject.bind(this))
}
这里的resolve和reject额外绑定this是因为在实际调用处上下文不在MyPromise中而是在new MyPromise((resolve)=>{resolve()}) 所以this指向会跟丢 手动指回来
第二个术语:Promise的状态
promise创建后有三个状态可供转换,它们之间的关系为:
所以我们可以定义三个状态来表示:
const PromiseState = {
PENDING: 'pending', // 等待态
FULFILLED: 'fulfilled', // 完成态
REJECT: 'reject', // 拒绝态
}
当resolve/reject时,当前状态为pending等待态时修改对应的状态并存储结果/拒因,在then方法中判断对应状态执行对应resolve/reject回调,于是有了以下代码:
function MyPromise(executor) {
let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
let promiseResult = null // 定义promise结果 初始为null
// 定义promise成功的resolve方法
function resolve(result) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.FULFILLED
promiseResult = result
}
}
// 定义promise失败的reject方法
function reject(reason) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.REJECT
promiseResult = reason
}
}
// then方法
this.then = function (onFulfilled, onRejected) {
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (promiseState === PromiseState.FULFILLED) {
onFulfilled(promiseResult)
}
if (promiseState === PromiseState.REJECT) {
onRejected(promiseResult)
}
}
// executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
executor && executor(resolve.bind(this), reject.bind(this))
}
测试一下MyPromise执行能否在then里拿到resolve的值
const promise = new MyPromise((res) => {
console.log('初始化promise')
res(1)
})
promise.then(
(res) => {
console.log('then-resolve执行了', res)
},
(rej) => {
console.log('then-reject执行了', rej)
}
)
到这里一个promise已经跑通了,尝试在executor中抛出一个错误:
const promise = new MyPromise((res) => {
console.log('初始化promise')
throw new Error('executor抛出的错误')
res(1)
})
promise.then(
(res) => {
console.log('then-resolve执行了', res)
},
(reason) => {
console.log('then-reject执行了', reason.message)
}
)
控制台打印了一个Uncaught Error , then方法的resolveCallback没能执行 预期这个错误应该是被我们捕捉的 catch一下executor执行错误 catch里直接走reject方法:
function MyPromise(executor) {
let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
let promiseResult = null // 定义promise结果 初始为null
// 定义promise成功的resolve方法
function resolve(result) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.FULFILLED
promiseResult = result
}
}
// 定义promise失败的reject方法
function reject(reason) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.REJECT
promiseResult = reason
}
}
// then方法
this.then = function (onFulfilled, onRejected) {
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (promiseState === PromiseState.FULFILLED) {
onFulfilled(promiseResult)
}
if (promiseState === PromiseState.REJECT) {
onRejected(promiseResult)
}
}
// 如果executor执行报错则catch底层错误直接走reject
try {
// executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
executor && executor(resolve.bind(this), reject.bind(this))
} catch (error) {
reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
}
}
catch后控制台打印没有未捕获的报错了:
错误抓到了 then方法的reject回调成功执行 拿到了拒因 到这错误捕捉完成!
给then传参不是函数时,预期会报错onFulfilled不是一个函数:
PromiseA+对executor的两个入参要求:
也就是要进行参数校验 如果传的不是函数就要忽略,这里的忽略不是不管了,如果onFulfilled不是函数则将result原地返回 如果onRejected不是函数则抛出拒因 保证promise.then能预期执行:
function MyPromise(executor){
...
// then方法
this.then = function (onFulfilled, onRejected) {
// 参数校验
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (promiseState === PromiseState.FULFILLED) {
onFulfilled(promiseResult)
}
if (promiseState === PromiseState.REJECT) {
onRejected(promiseResult)
}
}
}
const promise = new MyPromise((res, rej) => {
rej(new Error('默认reject抛出的error'))
})
promise.then((res) => res, undefined)
控制台抛出了错误 我们提供的默认throw reason在不提供onRejected时生效了
当前代码完整实现:
const PromiseState = {
PENDING: 'pending', // 等待态
FULFILLED: 'fulfilled', // 完成态
REJECT: 'reject', // 拒绝态
}
function MyPromise(executor) {
let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
let promiseResult = null // 定义promise结果 初始为null
// 定义promise成功的resolve方法
function resolve(result) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.FULFILLED
promiseResult = result
}
}
// 定义promise失败的reject方法
function reject(reason) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.REJECT
promiseResult = reason
}
}
// then方法
this.then = function (onFulfilled, onRejected) {
// 参数校验
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (promiseState === PromiseState.FULFILLED) {
onFulfilled(promiseResult)
}
if (promiseState === PromiseState.REJECT) {
onRejected(promiseResult)
}
}
// 如果executor执行报错则catch底层错误直接走reject
try {
// executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
executor && executor(resolve.bind(this), reject.bind(this))
} catch (error) {
reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
}
}
这个阶段的promise并不支持异步,看下面代码输出:
console.log(1)
const promise = new MyPromise((res, rej) => {
console.log(2)
res(3)
})
console.log(4)
promise.then((res) => {
console.log(res)
})
console.log(5)
原生promise的输出:
then里的3应该是最后输出的 因为他是异步的 PromiseA+对此的叙述:
onFulfilled和onRejected必须是在then方法被调用的那一轮事件循环之后的新执行栈中执行,也就是要放进一个事件队列等执行栈中的同步代码执行完再执行 js里实现这种机制用微任务/宏任务实现,本文用微任务实现
function MyPromise(executor){
...
// then方法
this.then = function (onFulfilled, onRejected) {
// 参数校验
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (promiseState === PromiseState.FULFILLED) {
// 将onFulfilled放入微任务队列
queueMicrotask(() => {
onFulfilled(promiseResult)
})
}
if (promiseState === PromiseState.REJECT) {
// 将onRejected放入微任务队列
queueMicrotask(() => {
onRejected(promiseResult)
})
}
}
}
3最后输出 then异步执行了!现在then是异步执行的了 如果executor中resolve也是在异步上下文中执行的,那就出问题了
function MyPromise(executor) {
let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
let promiseResult = null // 定义promise结果 初始为null
// 定义promise成功的resolve方法
function resolve(result) {
console.log('resolve执行了')
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.FULFILLED
promiseResult = result
}
}
// 定义promise失败的reject方法
function reject(reason) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.REJECT
promiseResult = reason
}
}
// then方法
this.then = function (onFulfilled, onRejected) {
// 参数校验
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (promiseState === PromiseState.FULFILLED) {
console.log('onFulfilled执行了')
queueMicrotask(() => {
onFulfilled(promiseResult)
})
}
if (promiseState === PromiseState.REJECT) {
queueMicrotask(() => {
onRejected(promiseResult)
})
}
}
// 如果executor执行报错则catch底层错误直接走reject
try {
// executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
executor && executor(resolve.bind(this), reject.bind(this))
} catch (error) {
reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
}
}
console.log(1)
const promise = new MyPromise((res, rej) => {
console.log(2)
setTimeout(() => {
res(3)
})
})
console.log(4)
promise.then((res) => {
console.log(res)
})
console.log(5)
将resolve放入微任务队列后的输出:
只有resolve执行了 then的onFulfilled没有执行导致3没有被打印 原因就在于resolve是异步执行的 所以执行then时promiseState还是pending状态并没有转变为fulfilled 导致if中的微任务执行onFulfilled没有走到 then方法里没有写状态为pending时要做什么 如果是pending时用两个数组将回调保存起来在resolve/reject调用时顺序遍历调用所有回调:
function MyPromise(executor) {
let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
let promiseResult = null // 定义promise结果 初始为null
// 定义存储then回调的数组
const onFulfilledCallbacks = []
const onRejectedCallbacks = []
// 定义promise成功的resolve方法
function resolve(result) {
console.log('resolve执行了')
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.FULFILLED
promiseResult = result
onFulfilledCallbacks.forEach((fn) => fn(result))
}
}
// 定义promise失败的reject方法
function reject(reason) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.REJECT
promiseResult = reason
onRejectedCallbacks.forEach((fn) => fn(reason))
}
}
// then方法
this.then = function (onFulfilled, onRejected) {
// 参数校验
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
// 如果是pending时保存回调解决异步执行resolve时then方法里的状态为pending导致不执行resolve/reject 在resolve/reject遍历保存的回调
if (promiseState === PromiseState.PENDING) {
onFulfilledCallbacks.push(onFulfilled)
onRejectedCallbacks.push(onRejected)
}
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (promiseState === PromiseState.FULFILLED) {
queueMicrotask(() => {
onFulfilled(promiseResult)
})
}
if (promiseState === PromiseState.REJECT) {
queueMicrotask(() => {
onRejected(promiseResult)
})
}
}
// 如果executor执行报错则catch底层错误直接走reject
try {
// executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
executor && executor(resolve.bind(this), reject.bind(this))
} catch (error) {
reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
}
}
console.log(1)
const promise = new MyPromise((res, rej) => {
console.log(2)
setTimeout(() => {
res(3)
})
})
console.log(4)
promise.then((res) => {
console.log(res)
})
console.log(5)
resolve(3)成功输出 回顾PromiseA+的调用时机 onFulfilled和onRejected要异步执行 所以还得改一下 保存回调时得包裹进微任务事件队列里保证其调用时是异步执行的:
function MyPromise(executor) {
let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
let promiseResult = null // 定义promise结果 初始为null
// 定义存储then回调的数组
const onFulfilledCallbacks = []
const onRejectedCallbacks = []
// 定义promise成功的resolve方法
function resolve(result) {
console.log('resolve执行了')
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.FULFILLED
promiseResult = result
onFulfilledCallbacks.forEach((fn) => fn(result))
}
}
// 定义promise失败的reject方法
function reject(reason) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (promiseState === PromiseState.PENDING) {
promiseState = PromiseState.REJECT
promiseResult = reason
onRejectedCallbacks.forEach((fn) => fn())
}
}
// then方法
this.then = function (onFulfilled, onRejected) {
// 参数校验
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
// 如果是pending时保存回调解决异步执行resolve时then方法里的状态为pending导致不执行resolve/reject 在resolve/reject遍历保存的回调
if (promiseState === PromiseState.PENDING) {
onFulfilledCallbacks.push(() => {
queueMicrotask(() => {
onFulfilled(promiseResult)
})
})
onRejectedCallbacks.push(() => {
queueMicrotask(() => {
onRejected(promiseResult)
})
})
}
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (promiseState === PromiseState.FULFILLED) {
queueMicrotask(() => {
onFulfilled(promiseResult)
})
}
if (promiseState === PromiseState.REJECT) {
queueMicrotask(() => {
onRejected(promiseResult)
})
}
}
// 如果executor执行报错则catch底层错误直接走reject
try {
// executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
executor && executor(resolve.bind(this), reject.bind(this))
} catch (error) {
reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
}
}
测试多次调用then:
const promise = new MyPromise((res, rej) => {
setTimeout(() => {
res(3)
})
})
promise.then((res) => {
console.log('then1:', res)
})
promise.then((res) => {
console.log('then2:', res)
})
then回调顺序执行成功,最后实现then方法的链式调用 在then方法中返回一个新创建的Promise实例对象,将之前的then代码放入新创建的Promise的executor中执行 根据PromiseA+规范对onFulfilled/onRejected函数返回值进行解析成一个非promise对象的纯净状态存储,PromiseA+规范对then链式调用和Promise解决过程(解析返回值成非Promise对象的纯净状态的过程)的描述:
PromiseA+ 滚动到Then方法那一栏查看
实现最终完整代码:
const PromiseState = {
PENDING: 'pending', // 等待态
FULFILLED: 'fulfilled', // 完成态
REJECT: 'reject', // 拒绝态
}
class MyPromise {
promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
promiseResult = null // 定义promise结果 初始为null
// 定义存储then回调的数组
onFulfilledCallbacks = []
onRejectedCallbacks = []
constructor(executor) {
// 如果executor执行报错则catch底层错误直接走reject
try {
// executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
executor && executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
}
}
// 定义promise成功的resolve方法
resolve(result) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (this.promiseState === PromiseState.PENDING) {
this.promiseState = PromiseState.FULFILLED
this.promiseResult = result
this.onFulfilledCallbacks.forEach((fn) => fn(result))
}
}
// 定义promise失败的reject方法
reject(reason) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (this.promiseState === PromiseState.PENDING) {
this.promiseState = PromiseState.REJECT
this.promiseResult = reason
this.onRejectedCallbacks.forEach((fn) => fn(reason))
console.error('Promise RejectError:', reason) // Promise执行异常打印 避免异常如果没有写reject回调什么都不会输出没有感知
}
}
/**
* @description promise解决过程 针对resolve()和reject()的返回值情况进行解析 拿到非promise的值 是promise就递归解析提取纯净状态(Promise的结果) PromiseA+中的以x为参数执行/拒绝Promise意思就是调用resolve/reject传入x
* @param {*} promise promise1.then返回的promise2对象
* @param {*} x promise1.then中onFulfilled/onRejected返回值
* @param {*} resolve promise2的resolve方法
* @param {*} reject promise2的reject方法
*/
resolvePromise(promise2, x, resolve, reject) {
/**
* promise2不能和x相等 避免循环引用
*/
if (promise2 === x) {
throw new TypeError('promise2不能和onFulfilled/onRejected值完全相等!')
}
if (x instanceof MyPromise) {
/**
* 如果 x 为 Promise ,解析x的状态继续递归解析
*/
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject)
} else if (
/**
* 如果x为对象/函数 查找x是否有then方法并尝试执行(判断有then方法看是否为类Promise对象 是就要解析 调用then拿到状态继续递归解析直到状态不是一个带then方法的类Promise对象为止) 如果访问x.then方法抛出了异常则reject并将error当拒因返回
* 如果有x.then方法则尝试调用 将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 this.resolvePromise ,第二个参数叫做 rejectPromise
*/
x !== null &&
(typeof x === 'function' || typeof x === 'object')
) {
let then = null
try {
then = x.then
} catch (error) {
reject(error)
}
if (typeof then === 'function') {
/**
* called: resolvePromise和rejectPromise是否被调用的标记 避免多次调用
* 如果 this.resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
*/
let called = false
try {
then.call(
x,
(y) => {
if (called) return
called = true
// 如果 this.resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
this.resolvePromise(promise2, y, resolve, reject)
},
(r) => {
if (called) return
called = true
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
reject(r)
}
)
} catch (error) {
if (called) {
return
}
called = true
/**
如果调用 then 方法抛出了异常 error:
如果 this.resolvePromise 或 rejectPromise 已经被调用(called=true),则忽略之否则以 error 为据因拒绝 promise
*/
reject(error)
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x)
}
} else {
// 如果 then 不是函数/对象,以 x 为参数执行 promise
resolve(x)
}
}
// then方法
then(onFulfilled, onRejected) {
const self = this
// 参数校验在返回的promise里做了 可以注释掉了
// onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
// onRejected =
// typeof onRejected === 'function'
// ? onRejected
// : (reason) => {
// throw reason
// }
// 创建下一个调用的promise对象返回 实现链式调用
const promise2 = new MyPromise((resolve, reject) => {
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (this.promiseState === PromiseState.FULFILLED) {
queueMicrotask(() => {
try {
// 如果不是函数则成功执行Promise(调resolve)原样返回想通的值
if (typeof onFulfilled !== 'function') {
resolve(this.promiseResult)
} else {
// 如果是函数则调用 并解析x
const x = onFulfilled(this.promiseResult)
this.resolvePromise(promise2, x, resolve, reject)
}
} catch (error) {
// 如果执行异常则拒绝执行Promise并返回相同的拒因error
reject(error)
}
})
}
if (this.promiseState === PromiseState.REJECT) {
queueMicrotask(() => {
try {
if (typeof onRejected !== 'function') {
reject(this.promiseResult)
} else {
const x = onRejected(this.promiseResult)
this.resolvePromise(promise2, x, resolve, reject)
}
} catch (error) {
reject(error)
}
})
}
// 如果是pending时保存回调解决异步执行resolve时then方法里的状态为pending导致不执行resolve/reject 在resolve/reject遍历保存的回调
if (this.promiseState === PromiseState.PENDING) {
this.onFulfilledCallbacks.push(() => {
queueMicrotask(() => {
try {
if (typeof onFulfilled !== 'function') {
resolve(this.promiseResult)
} else {
const x = onFulfilled(this.promiseResult)
this.resolvePromise(promise2, x, resolve, reject)
}
} catch (error) {
reject(error)
}
})
})
this.onRejectedCallbacks.push(() => {
queueMicrotask(() => {
try {
if (typeof onRejected !== 'function') {
reject(this.promiseResult)
} else {
const x = onRejected(this.promiseResult)
this.resolvePromise(promise2, x, resolve, reject)
}
} catch (error) {
reject(error)
}
})
})
}
})
return promise2
}
}
const promise = new MyPromise((res, rej) => {
res(3)
})
.then((res) => {
console.log('then1:', res)
return res + 2
})
.then((res) => {
console.log('then2:', res)
return res + 3
})
.then((res) => {
console.log('then3:', res)
})
控制台链式打印:
then链式调用成功!
最后附上promise六个静态方法的完整版代码:
const PromiseState = {
PENDING: 'pending', // 等待态
FULFILLED: 'fulfilled', // 完成态
REJECT: 'reject', // 拒绝态
}
class MyPromise {
promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
promiseResult = null // 定义promise结果 初始为null
// 定义存储then回调的数组
onFulfilledCallbacks = []
onRejectedCallbacks = []
constructor(executor) {
// 如果executor执行报错则catch底层错误直接走reject
try {
// executor是个函数 执行创建promise时new MyPromise(executor)传入的executor 将resolve方法和reject方法传入
executor && executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
}
}
// 定义promise成功的resolve方法
resolve(result) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (this.promiseState === PromiseState.PENDING) {
this.promiseState = PromiseState.FULFILLED
this.promiseResult = result
this.onFulfilledCallbacks.forEach((fn) => fn(result))
}
}
// 定义promise失败的reject方法
reject(reason) {
// 如果当前是等待态 则扭转状态 修改promise结果
if (this.promiseState === PromiseState.PENDING) {
this.promiseState = PromiseState.REJECT
this.promiseResult = reason
this.onRejectedCallbacks.forEach((fn) => fn(reason))
console.error('MyPromise RejectError:', reason) // Promise执行异常打印 避免异常如果没有写reject回调什么都不会输出没有感知
}
}
/**
* @description promise解决过程 针对resolve()和reject()的返回值情况进行解析 拿到非promise的值 是promise就递归解析提取纯净状态(Promise的结果) PromiseA+中的以x为参数执行/拒绝Promise意思就是调用resolve/reject传入x
* @param {*} promise promise1.then返回的promise2对象
* @param {*} x promise1.then中onFulfilled/onRejected返回值
* @param {*} resolve promise2的resolve方法
* @param {*} reject promise2的reject方法
*/
resolvePromise(promise2, x, resolve, reject) {
/**
* promise2不能和x相等 避免循环引用
*/
if (promise2 === x) {
throw new TypeError('promise2不能和onFulfilled/onRejected值完全相等!')
}
if (x instanceof MyPromise) {
/**
* 如果 x 为 MyPromise ,解析x的状态继续递归解析
*/
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject)
} else if (
/**
* 如果x为对象/函数 查找x是否有then方法并尝试执行(判断有then方法看是否为类Promise对象 是就要解析 调用then拿到状态继续递归解析直到状态不是一个带then方法的类Promise对象为止) 如果访问x.then方法抛出了异常则reject并将error当拒因返回
* 如果有x.then方法则尝试调用 将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 this.resolvePromise ,第二个参数叫做 rejectPromise
*/
x !== null &&
(typeof x === 'function' || typeof x === 'object')
) {
let then = null
try {
then = x.then
} catch (error) {
reject(error)
}
if (typeof then === 'function') {
/**
* called: resolvePromise和rejectPromise是否被调用的标记 避免多次调用
* 如果 this.resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
*/
let called = false
try {
then.call(
x,
(y) => {
if (called) return
called = true
// 如果 this.resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
this.resolvePromise(promise2, y, resolve, reject)
},
(r) => {
if (called) return
called = true
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
reject(r)
}
)
} catch (error) {
if (called) {
return
}
called = true
/**
如果调用 then 方法抛出了异常 error:
如果 this.resolvePromise 或 rejectPromise 已经被调用(called=true),则忽略之否则以 error 为据因拒绝 promise
*/
reject(error)
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x)
}
} else {
// 如果 then 不是函数/对象,以 x 为参数执行 promise
resolve(x)
}
}
// then方法
then(onFulfilled, onRejected) {
const self = this
// 参数校验在返回的promise里做了 可以注释掉了
// onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
// onRejected =
// typeof onRejected === 'function'
// ? onRejected
// : (reason) => {
// throw reason
// }
// 创建下一个调用的promise对象返回 实现链式调用
const promise2 = new MyPromise((resolve, reject) => {
// 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
if (this.promiseState === PromiseState.FULFILLED) {
queueMicrotask(() => {
try {
// 如果不是函数则成功执行Promise(调resolve)原样返回想通的值
if (typeof onFulfilled !== 'function') {
resolve(this.promiseResult)
} else {
// 如果是函数则调用 并解析x
const x = onFulfilled(this.promiseResult)
this.resolvePromise(promise2, x, resolve, reject)
}
} catch (error) {
// 如果执行异常则拒绝执行Promise并返回相同的拒因error
reject(error)
}
})
}
if (this.promiseState === PromiseState.REJECT) {
queueMicrotask(() => {
try {
if (typeof onRejected !== 'function') {
reject(this.promiseResult)
} else {
const x = onRejected(this.promiseResult)
this.resolvePromise(promise2, x, resolve, reject)
}
} catch (error) {
reject(error)
}
})
}
// 如果是pending时保存回调解决异步执行resolve时then方法里的状态为pending导致不执行resolve/reject 在resolve/reject遍历保存的回调
if (this.promiseState === PromiseState.PENDING) {
this.onFulfilledCallbacks.push(() => {
queueMicrotask(() => {
try {
if (typeof onFulfilled !== 'function') {
resolve(this.promiseResult)
} else {
const x = onFulfilled(this.promiseResult)
this.resolvePromise(promise2, x, resolve, reject)
}
} catch (error) {
reject(error)
}
})
})
this.onRejectedCallbacks.push(() => {
queueMicrotask(() => {
try {
if (typeof onRejected !== 'function') {
reject(this.promiseResult)
} else {
const x = onRejected(this.promiseResult)
this.resolvePromise(promise2, x, resolve, reject)
}
} catch (error) {
reject(error)
}
})
})
}
})
return promise2
}
// catch方法内部本质调的就是this.then(null, onRejected)
catch(onRejected) {
return this.then(null, onRejected)
}
// finally方法会在promise执行结束后必然执行 替代了一些一些收尾工作 以前需要resolve和reject里都写一遍callback逻辑 es2018出了finally方法解决这个问题
finally(callback) {
return this.then(callback, callback)
}
/**
* @description 接收一个值转为Promise对象
* @param value 要转为Promise对象的值
* @returns
*/
static resolve(value) {
// 如果是个Promise对象 则直接返回
if (value instanceof MyPromise) {
return value
}
// 如果是个thenable对象(包含then方法的对象) 则用resolve和reject去接管thenable的resolve和reject
/**
* MyPromise.resolve({
then: function (resolve) {
resolve('111') // thenable的resolve就是MyPromise的resolve接管的
},
}).then((r) => {
console.log(r) // 111
})
*/
if (value instanceof Object && 'then' in value) {
return new MyPromise((resolve, reject) => {
value.then(resolve, reject)
})
}
// 如果不是个Promise则以value为值返回一个Promise
return new MyPromise((resolve) => {
resolve(value)
})
}
/**
* @description 接收一个拒因返回一个带有拒因的promise对象
* @param value 要转为Promise对象的值
* @returns
*/
static reject(reason) {
return new MyPromise((_, reject) => {
reject(reason)
})
}
/**
* @description 并发执行promise 当所有promise都返回结果后完成promise 有一个拒绝promise则直接拒绝 不管其他有没有完成
* @params promises 可迭代的promise集合
*/
static all(promises) {
return new MyPromise((resolve, reject) => {
// 判断是否可迭代 不可迭代就reject
if (!Array.isArray(promises)) {
return reject(new Error('参数不可迭代!'))
} else {
const results = [] // 存储所有结果
let executeCount = 0 // 存储执行个数
promises.forEach((item, idx) => {
/**
* 用MyPromise.resolve将参数转promise对象统一调then处理 其内部判断了thenable对象和是否为promise对象 这里不用再判断thenable对象和promise对象的转换处理
*/
MyPromise.resolve(item).then(
(res) => {
executeCount++
// 将每一个结果顺序存储
results[idx] = res
// 执行完所有调resolve完成promise并返回所有结果的data数组
executeCount === promises.length && resolve(results)
},
(reason) => {
// 有一个失败就拒绝promise并返回拒因 不管其他promise是否完成
reject(reason)
}
)
})
}
})
}
/**
* @description 所有promise都resolve/reject时完成promise
* 和MyPromise.all的区别:
* 1.有reject不会拒绝promise 不管resolve还是reject都会执行
* 2.promise之间不相互依赖 reject不会打断其他promise执行 如果promise之间相互依赖则用all
* @params promises 可迭代的promise集合
*/
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
// 判断是否可迭代
if (!Array.isArray(promises)) {
throw new TypeError('参数不可迭代')
}
if (promises.length === 0) {
// 如果空数组则直接返回空数组
return resolve(promises)
}
const results = []
let executeCount = 0
promises.forEach((item, idx) => {
/**
* 原生allSettled将非promise值内部转换成了promise包装 这里也用MyPromise.resolve包装
* 用MyPromise.resolve接收参数转为一个promise对象 其内部判断了thenable对象和是否为promise对象 这里不用再判断thenable对象和promise对象的转换处理
*/
MyPromise.resolve(item).then(
(value) => {
executeCount++
// 每一项都构造一个当前promise状态和值的对象
results[idx] = {
status: PromiseState.FULFILLED,
value,
}
// 所有promise执行完就resolve
executeCount === promises.length && resolve(results)
},
(reason) => {
executeCount++
results[idx] = {
status: PromiseState.REJECT,
reason,
}
executeCount === promises.length && resolve(results)
}
)
})
})
}
/**
* @description 传入一个可迭代的promise集合 只要有一个promise完成/全部失败就返回一个成功的/失败的状态
*/
static any(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new Error('参数不可迭代'))
}
if (promises.length === 0) {
return reject(new Error('传入的数组不能为空'))
}
const errors = [] // 存储拒因
let executeCount = 0
promises.forEach((item, idx) => {
MyPromise.resolve(item).then(
(value) => {
/**
* 只要有一个成功就直接resolve
*/
return resolve(value)
},
(reason) => {
executeCount++
errors.push(reason)
/**
* 所有promise执行完将所有的拒因返回
*/
executeCount === promises.length && reject(errors)
}
)
})
})
}
/**
* @description 返回第一个完成/拒绝的promise
*/
static race(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject('参数不可迭代')
}
if (promises.length === 0) {
return reject('数组不能为空')
}
promises.forEach((item) => {
/**
* 用MyPromise.resolve包装每一个参数 MyPromise.resolve方法内部对非promise和类thenable对象进行了判断处理 统一转promise处理
* 用返回的promise的resolve和reject去接管每一个promise 返回第一个完成不管是成功/拒绝的promise
**/
MyPromise.resolve(item).then(resolve, reject)
})
})
}
}
function testChainingThen() {
const promise = new MyPromise((res, rej) => {
res(3)
})
.then((res) => {
console.log('then1:', res) // 3
return res + 2
})
.then((res) => {
console.log('then2:', res) // 5
return res + 3
})
.then((res) => {
console.log('then3:', res) // 8
})
}
function testResolve() {
// value为一个thenable对象时
MyPromise.resolve({
then: function (resolve) {
resolve(111)
},
}).then((r) => {
console.log(r) // 111
})
// value不为promise时
MyPromise.resolve(11).then((res) => {
console.log(res) // 11
})
// value为promise对象时
MyPromise.resolve(new MyPromise((resolve) => resolve(1))).then((res) => {
console.log(res) // 1
})
}
function testReject() {
MyPromise.reject('拒因').then(null, (reason) => {
console.log(reason) // 拒因
})
}
function testCatch(reason) {
new MyPromise((_, reject) => {
reject('报错测试catch')
}).catch((reason) => {
console.log(reason)
})
}
function testFinally() {
new MyPromise((resolve) => {
resolve('resolve finally')
})
.then((res) => {
console.log('res->', res)
})
.catch((error) => {
console.log('catch->', error)
})
.finally(() => {
console.log('finally callback执行')
})
}
function testAll() {
// 返回成功🌰
const promise1 = MyPromise.resolve(3)
const promise2 = {
then: (res) => res(42),
}
const promise3 = new MyPromise((resolve, reject) => {
setTimeout(resolve, 100, 'foo')
})
MyPromise.all([promise1, promise2, promise3]).then((values) => {
console.log(values) // [3, 42, 'foo']
})
// 返回失败🌰
// var p1 = new MyPromise((resolve, reject) => {
// setTimeout(resolve, 1000, 'one')
// })
// var p2 = new MyPromise((resolve, reject) => {
// setTimeout(resolve, 2000, 'two')
// })
// var p3 = new MyPromise((resolve, reject) => {
// setTimeout(resolve, 3000, 'three')
// })
// var p4 = new MyPromise((resolve, reject) => {
// setTimeout(resolve, 4000, 'four')
// })
// var p5 = new MyPromise((resolve, reject) => {
// reject('reject')
// })
// MyPromise.all([p1, p2, p3, p4, p5]).then(
// (values) => {
// console.log(values)
// },
// (reason) => {
// console.log(reason) // reject
// }
// )
}
function testAllSettled() {
const promise1 = MyPromise.resolve(3)
const promise2 = 1
const promises = [promise1, promise2]
MyPromise.allSettled(promises).then((results) =>
/**
* {status: 'fulfilled', value: 3}
* {status: 'fulfilled', value: 1}
*/
results.forEach((result) => console.log(result))
)
setTimeout(() => {
const p1 = MyPromise.resolve(3)
const p2 = new MyPromise((resolve, reject) =>
setTimeout(reject, 100, 'foo')
)
const ps = [p1, p2]
MyPromise.allSettled(ps).then((results) =>
/**
* {status: 'fulfilled', value: 3}
* {status: 'reject', reason: 'foo'}
*/
results.forEach((result) => console.log(result))
)
}, 1000)
}
function testAny() {
MyPromise.any([1, MyPromise.reject(2)]).then(
(res) => {
console.log(res)
},
(rej) => {
console.log(rej)
}
)
}
function testRace() {
const p1 = new MyPromise((resolve, reject) => setTimeout(resolve, 3000, 1))
const p2 = new MyPromise((resolve, reject) => setTimeout(resolve, 2000, 2))
const p3 = new MyPromise((resolve, reject) => setTimeout(resolve, 1000, 3))
MyPromise.race([p1, p2, p3]).then(
(value) => {
console.log(value) // 3
},
(reason) => {
console.log(reason)
}
)
}
// testChainingThen()
// testReject()
// testResolve()
// testCatch()
// testFinally()
// testAll()
// testAllSettled()
// testAny()
// testRace()