自定义promise超级详细版,看完不能再说自己不会了

96 阅读29分钟

看过很多版本的自定义promise,感觉都不够详细完整,特此整理一份完整版,附完整代码注释 每个实现代码块都可单独运行,并附上测试代码,可自行测试

一、Promise的核心用法

Promise - JavaScript | MDN

  1. 实例方法:then,catch,finally
  2. 静态方法:resolve,reject,race,all,allSettled,any,withResolvers
// 实例化 并管理异步任务
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
    // reject('error')
  }, 1000);
})

// then方法获取成功/失败结果
// 参数1:成功时执行的回调函数
// 参数2:失败时执行的回调函数
p.then(res => {
  console.log('res:', res)
  return 'success2'
}, err => {
  console.log('err:', err)
}).then(res2 => {
  console.log('res2:', res2)
})

二、自定义Promise核心功能

(一)构造函数

需求

  1. 实现MYPromise类,进行实例化
  2. 实例化时传入回调函数
    1. 回调函数立刻执行
    2. 回调函数接收函数resolvereject

实现步骤

  1. 定义类HMPromise
  2. 添加构造函数constructor,构造函数需要接收回调函数func
  3. 定义resolve/reject
  4. 执行回调函数
// 1. 定义类
class MYPromise {
  // 2. 添加构造函数,构造函数需要接收回调函数func
  constructor(func) {
    // 3. 定义resolve/reject
    const resolve = (result) => {
      console.log('resolve-执行啦:', result)
    }
    const reject = (result) => {
      console.log('reject-执行啦:', result)
    }

    // 4. 执行回调函数
    func(resolve, reject)
  }
}


// ------实例化测试------
const p = new MYPromise((resolve, reject) => {
  console.log('执行啦');
  resolve('success')
  reject('error')
})

// ------打印------
// 执行啦
// resolve-执行 success
// reject-执行 error

(二)state状态、成功和失败原因

需求

  1. MYPromise增加state属性,只能是如下3个值
    1. pending:待定,默认状态
    2. fulfilled:已兑现,操作成功
    3. rejected:已拒绝,操作失败
  2. MYPromise增加result属性,记录成功/失败原因
  3. 调用resolve时传入具体原因,如果状态为pending则更改状态为fulfilled并记录兑现原因
  4. 调用reject时传入具体原因,如果状态为pending则更改状态为rejected并记录拒绝原因
  5. 注意:状态不可逆

实现步骤

  1. 定义常量保存状态
  2. MYPromise中定义
    1. 属性:state保存状态,result成功/失败原因
    2. 修改state的私有方法,修改状态并记录result
    3. 注意:state只有在pending时,才可以修改,且不可逆
// 定义全局常量,方便使用
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  // 1. 添加状态,初始化状态为pending
  state = PENDING
  // 2. 添加原因
  result = undefined

  constructor(func) {
    // 3. 调整resolve/reject
    // 5. 状态不可逆
    // 改状态: pending->fulfilled
    // 记录原因
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
      }
    }
    // 4.改状态: pending->rejected
    // 记录原因
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
      }
    }

    func(resolve, reject)
  }
}


// ------实例化测试------
const p = new MYPromise((resolve, reject) => {
  resolve('success')  // pending -> fulfilled
  reject('error')   // pending -> rejected
})

// p.state 添加内部属性作为状态
// p.result 添加内部属性作为原因

(三)then方法-成功和失败回调

需求

  1. then方法的回调函数1: 状态变为fulfilled时触发,并获取成功结果
  2. then方法的回调函数2:状态变为rejected时触发,并获取失败原因
  3. then方法的回调函数1或2没有传递的特殊情况处理,参考:then方法的参数

实现步骤

  1. 增加then方法,根据不同的状态执行对应的回调函数,并传入result
    1. 参数1:成功的回调函数,onFulfilled
    2. 参数2:失败的回调函数,onRejected
  2. 判断参数
    1. 判断传入的onFulfilled和onRejected是否为函数
    2. 设置默认值(参考文档)
  3. 根据状态调用onFulfilled或onRejected并传入兑现或拒绝原因
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
      }
    }

    func(resolve, reject)
  }

  // 1. 添加then()实例方法
  then(onFulfilled, onRejected) {
    // 2. 参数判断(参考文档)
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    if (this.state === FULFILLED) {
      // 3.执行成功回调,并传入原因
      onFulfilled(this.result)
    } else if (this.state === REJECTED) {
      // 3.执行失败回调,并传入原因
      onRejected(this.result)
    }
  }
  
}



// ------实例化测试------
const p = new MYPromise((resolve, reject) => {
  resolve('success')  // pending -> fulfilled
  // reject('error')   // pending -> rejected
})

p.then(res => {
  console.log("成功回调", res);
}, err => {
  console.log("失败回调", err);
})

// 此时只传了一个参数,onRejected 会抛出错误
p.then( err => {
  console.log("失败回调", err);  // Uncaught error
})

(四)then方法-异步和多次调用

需求

  1. 实例化传入的回调函数,内部支持异步操作
  2. then方法支持多次调用

实现步骤

  1. 定义属性:保存传入的回调函数:[]
  2. MYPromise添加私有属性#handlers
    1. 保存then方法调用时状态为pending的回调函数
    2. 格式为对象数组:[{onFulfilled,onRejected}...]
  3. 调用成功回调:resolve内部,取出数组#handlers中的所有onFulfilled回调函数进行调用
  4. 调用失败回调:reject内部,取出数组#handlers中的所有onRejected回调函数进行调用
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  // 1. 定义实例属性,私有属性,只能在类的内部调用,保存传入的回调函数:[]
  #handlers = [] // [{onFulfilled,onRejected}...]

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        // 3. 调用成功回调
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        // 4. 调用失败回调
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    if (this.state === FULFILLED) {
      onFulfilled(this.result)
    } else if (this.state === REJECTED) {
      onRejected(this.result)
    } else if (this.state === PENDING) {
      // 此时状态没有改变说明没有调用,为异步状态
      // 2. 保存回调函数
      this.#handlers.push({
        onFulfilled, onRejected
      })
    }
  }
}


// ------实例化测试------
  const p = new MYPromise((resolve, reject) => {
    setTimeout(() => {
      // resolve('success')  
      reject('error')
    }, 2000)
  })


  p.then(res => {
    console.log("then1", res);
  }, err => {
    console.log("then1", err); // then1 error
  })

  p.then(res => {
    console.log("then2", res);
  }, err => {
    console.log("then2", err);// then2 error
  })

(五)then方法-异步任务

需求

  1. 如下代码打印结果为1,3,2,期望结果应为1,2,3
  2. 核心:让then方法的回调函数以异步任务的方式执行
console.log('1')
const p = new MYPromise((resolve, reject) => {
  resolve('3')
})

p.then(res => {
  console.log(res)
})
console.log('2')

参考资料

以上都可以实现异步任务

  1. queueMicrotask :新式浏览器均支持,node11开始支持,ie不支持
  2. MutationObserver :新式浏览器均支持,ie11开始支持
  3. setImmediate:新式浏览器只有edge支持。ie10开始支持
  4. setTimeout:浏览器支持,node支持

实现步骤

  1. 封装执行异步任务的函数
  2. 定义函数传入异步任务(回调函数)
  3. 内部根据实际情况判断并使用开启异步任务的api即可,比如queueMicrotask,MutationObserver
  4. 调用的api可以根据实际情况进行调整
  5. 如果都无法执行,使用setTimeout兜底
  6. 调整then中的逻辑,fulFilled,rejected,pending3种状态时的回调函数,使用封装的函数包装一次
// 1. 定义函数
function runAsynctask(callback) {
  // 2. 调用核心api(queueMicrotask,MutationObserver,setTimeout)
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    // 3. 使用封装函数调用
    if (this.state === FULFILLED) {
      runAsynctask(() => {
        onFulfilled(this.result)
      })
    } else if (this.state === REJECTED) {
      runAsynctask(() => {
        onRejected(this.result)
      })
    } else if (this.state === PENDING) {
      this.#handlers.push({
        onFulfilled: () => {
          runAsynctask(() => {
            onFulfilled(this.result)
          })
        }, onRejected: () => {
          runAsynctask(() => {
            onRejected(this.result)
          })
        }
      })
    }
  }
}


// ------实例化测试------
console.log('1')
const p = new MYPromise((resolve, reject) => {
  resolve('3')
})

p.then(res => {
  console.log(res)
})
console.log('2')

// -----打印结果-------
// 1
// 2
// 3

(六)链式编程-fulfilled状态-返回值+异常

需求

  1. then的链式编程
  2. 目前只考虑then的第一个回调函数
    1. 返回普通值
    2. 内部出现异常
const p = new MYPromise((resolve, reject) => {
  resolve(1)
})
p.then(res => {
  console.log(res)
  // throw 'throw-error'
  return 2
}).then(res => {
  console.log(res) // 2
}, err => {
  console.log(err)
})

实现步骤

  1. 调整then方法,返回一个新的MYPromise对象
  2. 使用try-catch捕获异常,并通过reject传递
  3. 内部获取onFulfilled的执行结果,并通过resolve传递
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    // 1. 链式调用,必须返回新Promise实例
    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          // 2. 获取返回值
          try {
            const x = onFulfilled(this.result)
            // 2.1 处理返回值,通过resolve传递
            resolve(x)
          } catch (error) {
            // 2.2 处理异常,通过reject传递
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          onRejected(this.result)
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              onFulfilled(this.result)
            })
          }, onRejected: () => {
            runAsynctask(() => {
              onRejected(this.result)
            })
          }
        })
      }
    })

    return p2
  }
}

(七)链式编程-fulfilled状态-返回Promise的情况

需求:

  1. then的链式编程
  2. 目前只考虑then的第一个回调函数
    1. 返回Promise
const p = new MYPromise((resolve, reject) => {
  resolve(1)
})

p.then(res => {
  return new MYPromise((resolve, reject) => {
    resolve(2)
    // reject('error')
  })
}).then(res => {
  console.log('p2:', res) // 2
}, err => {
  console.log('p2:', err) // error
})

实现步骤

  1. 判断是否为MYPromise实例
  2. 调用then方法依次传入回调函数
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            // 1.处理返回Promise
            if (x instanceof MYPromise) {
              // console.log('MYPromise实例')
              // 2. 调用then方法
              // x.then(res => console.log(res), err => console.log(err))
              x.then(res => resolve(res), err => reject(err))
            } else {
              resolve(x)
            }
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          onRejected(this.result)
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              onFulfilled(this.result)
            })
          }, onRejected: () => {
            runAsynctask(() => {
              onRejected(this.result)
            })
          }
        })
      }
    })

    return p2
  }
}

(八)链式编程-fulfilled状态-重复引用 需求:

  1. then中返回的then方法返回的Promise实例报错
  2. 注:下列代码中的p2
const p = new MYPromise((resolve, reject) => {
  resolve(1)
})
const p2 = p.then(res => {
  return p2
})
p2.then(
  res => { },
  err => console.log('err:', err))

实现步骤

  1. 判断是否相同,抛出异常
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            // 1. 处理重复引用
            if (x === p2) {
              // console.log('返回了p2')
              // 2. 抛出错误 Chaining cycle detected for promise #<Promise>
              throw new TypeError('Chaining cycle detected for promise #<Promise>')
            }            
            if (x instanceof MYPromise) {
              x.then(res => resolve(res), err => reject(err))
            } else {
              resolve(x)
            }
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          onRejected(this.result)
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              onFulfilled(this.result)
            })
          }, onRejected: () => {
            runAsynctask(() => {
              onRejected(this.result)
            })
          }
        })
      }
    })
    return p2
  }
}

(八)链式编程-rejected状态

rejected状态和fulfilled状态处理方式是一样的。 需求

  1. then的第二个回调函数,执行reject时的链式编程
const p = new MYPromise((resolve, reject) => {
  reject(1)
})
const p2 = p.then(undefined, err => {
  throw 'error'
  // return p2
  // return 2
  // return new MYPromise((resolve, reject) => {
  //   resolve('MYPromise-2')
  // })
})
p2.then(res => {
  console.log('p2-res:', res)
}, err => {
  console.log('p2-err:', err)
})

实现步骤

  1. 处理异常:onRejected的异常
  2. 获取返回值:onRejected的返回值
  3. fulfilled状态中的处理逻辑抽取为函数resolvePromise并复用
  4. fulfilledrejected状态中调用函数resolvePromise
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 3. 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            // 4. 调用函数
            resolvePromise(p2, x, resolve, reject)            
            // if (x === p2) {
            //   throw new TypeError('Chaining cycle detected for promise #<Promise>')
            // }            
            // if (x instanceof MYPromise) {
            //   x.then(res => resolve(res), err => reject(err))
            // } else {
            //   resolve(x)
            // }
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          // 1. 处理异常
          try {
            // 2. 获取返回值
            const x = onRejected(this.result)
            // console.log('x:', x)
            // 4. 调用函数
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              onFulfilled(this.result)
            })
          }, onRejected: () => {
            runAsynctask(() => {
              onRejected(this.result)
            })
          }
        })
      }
    })
    return p2
  }
}

(九)链式编程-pending状态

pending状态与rejected状态、fulfilled状态处理方式是一样的。

需求

  1. then的第二个回调函数,执行reject时的链式编程
const p = new MYPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 2000)
})
const p2 = p.then(res => {
  throw 'error'
  // return p2
  // return 2
  // return new MYPromise((resolve, reject) => {
  //   resolve('resolve-2')
  //   // reject('reject-2')
  // })
})
p2.then(res => {
  console.log('p2-res:', res)
}, err => {
  console.log('p2-err:', err)
})

实现步骤

  1. 处理异常:onRejected的异常
  2. 获取返回值:onRejected的返回值
  3. fulfilled状态中的处理逻辑抽取为函数resolvePromise并复用
  4. fulfilledrejected状态中调用函数resolvePromise
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              // 1. 处理异常
              try {
                // 2.获取返回值
                const x = onFulfilled(this.result)
                // 3.调用函数
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              // 1. 处理异常
              try {
                // 2.获取返回值
                const x = onRejected(this.result)
                // 3.调用函数
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }
}

(十)总结—附完整版代码

以上为自定义Promise核心功能,面试手写一般到这里就可以 完整代码

// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }
}

三、自定义Promise实例方法和静态方法

(一)实例方法-catch

需求:

  1. 实现实例方法catch,可以实现如下调用
const p = new MYPromise((resolve, reject) => {
  reject('reject-error')
  // throw 'throw-error'
})

p.then(res => {
  console.log('res:', res)
}).catch(err => {
  console.log('err:', err)
})

实现步骤

  1. 参考文档,catch等同于:then(undefined,onRjected)
  2. 直接添加catch方法,内部调用then
  3. 使用try-catch包裹constructor中的func捕获异常
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }


    /**
   * catch方法
   * 1. 内部调用then方法
   * 2. 处理异常
   * */
  catch(onRejected) {
    // 1. 内部调用then方法
    return this.then(undefined, onRejected)
  }
}


// ------------- 实例化测试 -------------
const p = new MYPromise((resolve, reject) => {
  // reject('reject-error')
  throw 'throw-error'
})

p.then(res => {
  console.log('res:', res)
}).catch(err => {
  console.log('err:', err)
})

(二)实例方法-finally

finally和catch处理方式是一样的,只是接收的参数不一样 需求:

  1. 无论成功失败都会执行finally的回调函数
  2. 回调函数不接受任何参数

实现步骤 参考文档:finally方法类似于调用then(onFinally,onFinally),且不接受任何回调函数

// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  /**
   * finally方法
   * 1. 内部调用then方法
   * */
  finally(onFinally) {
    return this.then(onFinally, onFinally)
  }
}


// ------------- 实例化测试 -------------
const p = new MYPromise((resolve, reject) => {
  // resolve('resolve-res')
  // reject('reject-error')
  // throw 'throw-error'
})
p.then(res => {
  console.log('res:', res)
}).catch(err => {
  console.log('err:', err)
}).finally(() => {
  console.log('finally')
})

(三)静态方法-resolve

Class(类)的方法都会被实例继承,但是对于在方法名前面加了static关键字的方法,则不能直接被实例继承,只能通过类来调用,称之为“静态方法”。 需求

  1. 将给定的值转换为一个 Promise,返回一个带有成功原因的Promise对象
MYPromise.resolve(new MYPromise((resolve, reject) => {
  // resolve('resolve')
  // reject('reject')
  // throw 'error'
})).then(res => {
  console.log('res:', res)
}, err => {
  console.log('err:', err)
})
  
MYPromise.resolve('测试').then(res => {
  console.log(res)
})

实现步骤

  1. 通过static关键字添加静态方法resolve,接收参数value
  2. 内部判断传入的值
  3. 如果是Promise实例,直接返回
  4. 其他的值,创建Promise实例并返回,内部通过resolve(value)传递value
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  finally(onFinally) {
    return this.then(onFinally, onFinally)
  }

  /**
   * 静态方法-resolve
   * */
  static resolve(value) {
    // 1 Promise直接返回
    if (value instanceof MYPromise) {
      return value;
    }

    // 2 转为Promise并返回(fulfilled状态)
    return new MYPromise((resolve, reject) => {
      resolve(value);
    });
  }  
}


// ------------- 测试 -------------
MYPromise.resolve(new MYPromise((resolve, reject) => {
  // resolve('resolve')
  // reject('reject')
  // throw 'error'
})).then(res => {
  console.log('res:', res)
}, err => {
  console.log('err:', err)
})
  
MYPromise.resolve('测试').then(res => {
  console.log(res)
})

(四)静态方法-reject

需求

  1. 返回一个已拒绝(rejected)的 Promise 对象

实现步骤

  1. 添加静态方法
  2. 返回rejected状态的Promise
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  finally(onFinally) {
    return this.then(onFinally, onFinally)
  }

  static resolve(value) {
    if (value instanceof MYPromise) {
      return value;
    }
    return new MYPromise((resolve, reject) => {
      resolve(value);
    });
  }  

  /**
   * 静态方法-reject
   * 1. 返回rejected状态的Promise
   * */
  static reject(value) {
    return new MYPromise((resolve,reject)=>{
      reject(value)
    })
  }
}



// ------------- 测试代码 -------------
MYPromise.reject("error22").catch((res) => {
  console.log(res);
});

(五)静态方法-race

需求:

  1. 接收Promise数组,数组中第一个Promise敲定时,获取成功/失败结果
  2. 传入的参数不是数组,直接报错

实现步骤

  1. 返回Promise
  2. 判断是否未数组,不是直接报错
  3. 等待第一个敲定
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  finally(onFinally) {
    return this.then(onFinally, onFinally)
  }

  static resolve(value) {
    if (value instanceof MYPromise) {
      return value;
    }
    return new MYPromise((resolve, reject) => {
      resolve(value);
    });
  }  

  static reject(value) {
    return new MYPromise((resolve,reject)=>{
      reject(value)
    })
  }


  /**
   * 静态方法-race
   * 1. 返回Promise
   * 2. 判断是否为数组 错误信息:Argument is not iterable
   * 3. 等待第一个敲定
   * */
    static race(promise) {
      return new MYPromise((resolve, reject) => {
        // 2. 判断是否为数组
        if (!Array.isArray(promise)) {
          return reject(new TypeError("Argument is not iterable"));
        }
        // 3. 等待第一个敲定
        promise.forEach((p) => {
          MYPromise.resolve(p).then(
            (res) => {
              resolve(res);
            },
            (err) => {
              reject(err);
            }
          );
        });
      });
    }
  
}



// ------------- 测试代码 -------------
const p1 = new MYPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 2000)
})

const p2 = new MYPromise((resolve, reject) => {
  setTimeout(() => {
    reject(2)
  }, 1000)
})

MYPromise.race([p1, p2, '测试']).then((res) => {
  console.log('res:', res)  // 测试
}, err => {
  console.log('err:', err)
})

(六)静态方法-all

需求:

  1. 接收Promise数组
    1. 所有Promise都成功时,返回一个成功的Promise对象及成功数组
    2. 任何一个Promise失败,返回一个失败的Promise对象及第一个失败原因

实现步骤

  1. 添加静态方法all
  2. 内部返回Promise实例,在返回的Promise实例中:
    1. 判断参数是否为数组,不是通过reject传递错误
    2. 空数组直接以空数组为结果进行兑现
    3. 遍历Promise数组,通过resolve静态方法等待结果
      1. 处理全部兑现:
        1. 通过数组记录结果,用索引的方式来添加,目的是保证结果的顺序和Promise数组的顺序一致
        2. 通过兑现次数进行判断,因为是通过索引的方式记录结果,如果第一次兑现的是最后一个,那么数组的长度就已经和Promise数组的长度一致了,所以需要通过兑现次数来进行判断
      2. 任意一个拒绝,调用reject传递拒绝原因
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  finally(onFinally) {
    return this.then(onFinally, onFinally)
  }

  static resolve(value) {
    if (value instanceof MYPromise) {
      return value;
    }
    return new MYPromise((resolve, reject) => {
      resolve(value);
    });
  }  

  static reject(value) {
    return new MYPromise((resolve,reject)=>{
      reject(value)
    })
  }

  static race(promise) {
    return new MYPromise((resolve, reject) => {
      if (!Array.isArray(promise)) {
        return reject(new TypeError("Argument is not iterable"));
      }
      promise.forEach((p) => {
        MYPromise.resolve(p).then(
          (res) => {
            resolve(res);
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }


    /**
     * 静态方法-all
     *  1. 返回Promise实例
     *  2. 判断是否为数组 错误信息:Argument is not iterable
     *  3. 空数组直接兑现
     *  4. 处理全部兑现
     *    4.1 记录结果:索引来记录,保证结果的顺序和Promise数组的顺序一致
     *    4.2 判断全部兑现:通过兑现的次数进行判断,保证可以获取到所有的结果
     *  5. 处理第一个拒绝
     * */
    static all(promises) {
      // 1. 返回Promise实例
      return new MYPromise((resolve, reject) => {
        // 2. 判断是否为数组 错误信息:Argument is not iterable
        if (!Array.isArray(promises)) {
          return reject(new TypeError("Argument is not iterable"));
        }
        // 3. 空数组直接兑现
        promises.length === 0 && resolve(promises);
        // 4. 处理全部兑现
        const result = [];
        let count = 0;
        promises.forEach((p, index) => {
          MYPromise.resolve(p).then(
            (res) => {
              // 4.1 记录结果:索引来记录,保证结果的顺序和Promise数组的顺序一致
              result[index] = p;
              // 4.2 判断全部兑现:通过兑现的次数进行判断,保证可以获取到所有的结果
              count++;
              count === promises.length && resolve(result);
            },
            (err) => {
              // 5. 处理第一个拒绝
              reject(err)
            }
          );
        });
      });
    }
  
}



// ------------- 测试代码 -------------
  const p1 = MYPromise.resolve(1);
  const p2 = new MYPromise((resolve, reject) => {
    setTimeout(() => {
      // resolve(2)
      reject("error");
    }, 1000);
  });
  const p3 = 3;

  MYPromise.all([p1, p2, p3]).then(
    (res) => {
      // MYPromise.all().then(res => {
      // MYPromise.all([]).then(res => {
      console.log("res:", res);
    },
    (err) => {
      console.log("err:", err);
    }
  );

(七)静态方法-allSettled

需求

  1. 传入Promise数组,当所有对象都已敲定时
  2. 返回一个新的Promise对象及以数组形式保存的结果

实现步骤 做法和all方法类似,区别是要获取全部敲定的结果(成功/拒绝),以及获取的结果是对象形式

  1. 添加静态方法allSettled
  2. 内部返回Promise实例,在返回的Promise实例中:
  3. 判断参数是否为数组,不是通过reject传递错误
  4. 空数组直接以空数组为结果进行兑现
  5. 遍历Promise数组,通过resolve静态方法等待敲定结果
  6. 等待全部敲定:并记录结果,根据兑现和拒绝将如下格式的内容通过索引的方式的记录到数组中
  7. 处理兑现:{state:FULFILLED,value:'xxx'}
  8. 处理拒绝:{state:REJECTED,reason:'xxx'}
  9. 根据敲定的次数判断是否全部敲定,全部敲定之后,通过resolve传递结果数组
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  finally(onFinally) {
    return this.then(onFinally, onFinally)
  }

  static resolve(value) {
    if (value instanceof MYPromise) {
      return value;
    }
    return new MYPromise((resolve, reject) => {
      resolve(value);
    });
  }  

  static reject(value) {
    return new MYPromise((resolve,reject)=>{
      reject(value)
    })
  }

  static race(promise) {
    return new MYPromise((resolve, reject) => {
      if (!Array.isArray(promise)) {
        return reject(new TypeError("Argument is not iterable"));
      }
      promise.forEach((p) => {
        MYPromise.resolve(p).then(
          (res) => {
            resolve(res);
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }


    static all(promises) {
      return new MYPromise((resolve, reject) => {
        if (!Array.isArray(promises)) {
          return reject(new TypeError("Argument is not iterable"));
        }
        promises.length === 0 && resolve(promises);
        const result = [];
        let count = 0;
        promises.forEach((p, index) => {
          MYPromise.resolve(p).then(
            (res) => {
              result[index] = p;
              count++;
              count === promises.length && resolve(result);
            },
            (err) => {
              reject(err)
            }
          );
        });
      });
    }


    /**
     * 静态方法-allSettled
     * 1. 返回Promise
     * 2. 数组判断 错误信息: Argument is not iterable
     * 3. 为空直接敲定
     * 4. 等待全部敲定
     *  4.1 记录结果
     *  4.2 处理兑现{status:'fulfilled',value:''}
     *  4.3 处理拒绝{status:'rejected',reason:''}
     * */
    static allSettled(promises) {
      return new MYPromise((resolve, reject) => {
        // 2. 数组判断 错误信息: Argument is not iterable
        if (!Array.isArray(promises)) {
          return reject(new TypeError("Argument is not iterable"));
        }
        // 3. 为空直接敲定
        promises.length === 0 && resolve(promises);
        // 4. 等待全部敲定
        const result = [];
        let count = 0;
        promises.forEach((p, index) => {
          MYPromise.resolve(p).then(
            (res) => {
              // 4.1 记录结果:索引来记录,保证结果的顺序和Promise数组的顺序一致
              result[index] = { status: FULFILLED, value: res };
              count++
              count === promises.length && resolve(result);
            },
            (err) => {
              result[index] = { status: REJECTED, reason: err };
              count++
              count === promises.length && resolve(result);
            }
          );
        });
      });
      
}



// ------------- 测试代码 -------------
  const p1 = MYPromise.resolve(1);
  const p2 = new MYPromise((resolve, reject) => {
    setTimeout(() => {
      // resolve(2)
      reject("error");
    }, 1000);
  });
  const p3 = 3;

  MYPromise.all([p1, p2, p3]).then(
    (res) => {
      // MYPromise.all().then(res => {
      // MYPromise.all([]).then(res => {
      console.log("res:", res);
    },
    (err) => {
      console.log("err:", err);
    }
  );

(八)静态方法-any

需求

  1. 传入Promise数组,
  2. 任何一个Promise对象敲定时,返回一个新的Promise对象,及对应的结果
  3. 所有Promise都被拒绝时,返回一个包含所有拒绝原因的AggregateError错误数组

实现步骤 做法和all方法也有点类似,区别是获取第一个兑现,或者是全部拒绝

  1. 添加静态方法any
  2. 内部返回Promise实例,在返回的Promise实例中:
    1. 判断参数是否为数组,不是通过reject传递错误
    2. 空数组直接以空数组为结果进行兑现
  3. 遍历Promise数组,通过resolve静态方法等待结果
    1. 第一个兑现,通过resolve传递兑现结果
    2. 全部拒绝:
      1. 定义数组,保存拒绝原因,通过索引记录,目的是保证顺序和Promise数组一致
      2. 通过次数判断是否全部拒绝,当全部拒绝时,通过reject传递AggregateError类型的错误,并将拒绝原因数组传递进去即可
// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  finally(onFinally) {
    return this.then(onFinally, onFinally)
  }

  static resolve(value) {
    if (value instanceof MYPromise) {
      return value;
    }
    return new MYPromise((resolve, reject) => {
      resolve(value);
    });
  }  

  static reject(value) {
    return new MYPromise((resolve,reject)=>{
      reject(value)
    })
  }

  static race(promise) {
    return new MYPromise((resolve, reject) => {
      if (!Array.isArray(promise)) {
        return reject(new TypeError("Argument is not iterable"));
      }
      promise.forEach((p) => {
        MYPromise.resolve(p).then(
          (res) => {
            resolve(res);
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }

  static all(promises) {
    return new MYPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError("Argument is not iterable"));
      }
      promises.length === 0 && resolve(promises);
      const result = [];
      let count = 0;
      promises.forEach((p, index) => {
        MYPromise.resolve(p).then(
          (res) => {
            result[index] = p;
            count++;
            count === promises.length && resolve(result);
          },
          (err) => {
            reject(err)
          }
        );
      });
    });
  }

  static allSettled(promises) {
    return new MYPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError("Argument is not iterable"));
      }
      promises.length === 0 && resolve(promises);
      const result = [];
      let count = 0;
      promises.forEach((p, index) => {
        MYPromise.resolve(p).then(
          (res) => {
            result[index] = { status: FULFILLED, value: res };
            count++
            count === promises.length && resolve(result);
          },
          (err) => {
            result[index] = { status: REJECTED, reason: err };
            count++
            count === promises.length && resolve(result);
          }
        );
      });
    });
  }


    /**
     * 静态方法-any
     * 1. 返回Promise,数组判断 错误信息: Argument is not iterable
     * 2. 空数组直接拒绝 AggregateError([错误原因1..],All promises were rejected)
     * 3. 等待结果
     *  3.1 第一个兑现
     *  3.2 全部拒绝
     */
    static any(promises) {
      return new MYPromise((resolve, reject) => {
        // 1. 返回Promise,数组判断 错误信息: Argument is not iterable
        if (!Array.isArray(promises)) {
          return reject(new TypeError("Argument is not iterable"));
        }
				// 2. 空数组直接拒绝 AggregateError([错误原因1..],All promises were rejected)
        promises.length === 0 &&
          reject(
            new AggregateError(promises, "All promises were rejected")
          );

        // 3.等待结果
        const errors = [];
        let count = 0;
        promises.forEach((p, index) => {
          MYPromise.resolve(p).then(
            (res) => {
              // 3.1 第一个兑现
              resolve(res);
            },
            (err) => {
              // 3.2 全部拒绝
              errors[index] = err;
              count++;
              count === promises.length &&
                reject(
                  new AggregateError(errors, "All promises were rejected")
                );
            }
          );
        });
      });
    }
  
}



// ------------- 测试代码 -------------
  const p1 = new MYPromise((resolve, reject) => {
    setTimeout(() => {
      reject(1);
    }, 2000);
  });
  // const p2 = 2
  const p2 = MYPromise.reject(2);
  const p3 = new MYPromise((resolve, reject) => {
    setTimeout(() => {
      // resolve(3)
      reject(3);
    }, 1000);
  });

  MYPromise.any([p1, p2, p3]).then(
    (res) => {
      // MYPromise.any().then(res => {
      // MYPromise.any([]).then(res => {
      console.log("res:", res);
    },
    (err) => {
      console.dir(err);
    }
  );

(九)总结—附完整版代码

自定义promise现在已经是面试必备手写题了,每个面试者都需要掌握

// 封装的异步函数
function runAsynctask(callback) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '监测元素改变,才会执行'
  } else {
    setTimeout(callback, 0)
  }
}


// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
  if (x === p2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>')
  }
  if (x instanceof MYPromise) {
    x.then(res => resolve(res), err => reject(err))
  } else {
    resolve(x)
  }
}


const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MYPromise {
  state = PENDING
  result = undefined
  #handlers = []

  constructor(func) {
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })        
      }
    }
    
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }

    func(resolve, reject)
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    const p2 = new MYPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        runAsynctask(() => {
          try {
            const x = onFulfilled(this.result)
            resolvePromise(p2, x, resolve, reject)            
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === REJECTED) {
        runAsynctask(() => {
          try {
            const x = onRejected(this.result)
            resolvePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.state === PENDING) {
        this.#handlers.push({
          onFulfilled: () => {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }, onRejected: () => {
            runAsynctask(() => {
              try {
                const x = onRejected(this.result)
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })
    return p2
  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  finally(onFinally) {
    return this.then(onFinally, onFinally)
  }

  static resolve(value) {
    if (value instanceof MYPromise) {
      return value;
    }
    return new MYPromise((resolve, reject) => {
      resolve(value);
    });
  }  

  static reject(value) {
    return new MYPromise((resolve,reject)=>{
      reject(value)
    })
  }

  static race(promise) {
    return new MYPromise((resolve, reject) => {
      if (!Array.isArray(promise)) {
        return reject(new TypeError("Argument is not iterable"));
      }
      promise.forEach((p) => {
        MYPromise.resolve(p).then(
          (res) => {
            resolve(res);
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }

  static all(promises) {
    return new MYPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError("Argument is not iterable"));
      }
      promises.length === 0 && resolve(promises);
      const result = [];
      let count = 0;
      promises.forEach((p, index) => {
        MYPromise.resolve(p).then(
          (res) => {
            result[index] = p;
            count++;
            count === promises.length && resolve(result);
          },
          (err) => {
            reject(err)
          }
        );
      });
    });
  }

  static allSettled(promises) {
    return new MYPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError("Argument is not iterable"));
      }
      promises.length === 0 && resolve(promises);
      const result = [];
      let count = 0;
      promises.forEach((p, index) => {
        MYPromise.resolve(p).then(
          (res) => {
            result[index] = { status: FULFILLED, value: res };
            count++
            count === promises.length && resolve(result);
          },
          (err) => {
            result[index] = { status: REJECTED, reason: err };
            count++
            count === promises.length && resolve(result);
          }
        );
      });
    });
  }


  static any(promises) {
    return new MYPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError("Argument is not iterable"));
      }
      promises.length === 0 &&
        reject(
          new AggregateError(promises, "All promises were rejected")
        );
      const errors = [];
      let count = 0;
      promises.forEach((p, index) => {
        MYPromise.resolve(p).then(
          (res) => {
            resolve(res);
          },
          (err) => {
            errors[index] = err;
            count++;
            count === promises.length &&
              reject(
                new AggregateError(errors, "All promises were rejected")
              );
          }
        );
      });
    });
  }
  
}

(十)最新特性补充

最新特性补充 Promise.withResolvers()

Promise.withResolvers()  // 完全等同于以下代码


let resolve, reject;
const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

这里我们可以看到,如果我们想使用promise 的内部res和rej,需要定义变量来接收,Promise.withResolvers()返回一个对象,可以直接来调用,但需要浏览器注意兼容性

Snipaste_2024-01-22_23-00-45.png

const {promise,resovle,reject} = Promise.withResolvers()

function func(){
  resolve('调用了')
}
func()

promise.then(res=>{
  console.log(res)
})