Promise深入浅出及源码实现

643 阅读15分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

Promise是什么

Promise是ES6推出的一个内置JS类,用于异步编程,相较于回调函数的方式,使用起来更优雅、更合理。

优雅.png

Promise中文释义是承诺的意思,Promise有三种状态:pending(进行中)、fulfilled(成功,即被resole了)、rejected(失败,即被reject或报错了),它的状态改变是单向的、不可逆的。

Promise的用法

基本用法

  // 被resolve的情况
  const promise1 = new Promise((resolve, reject) => {
    resolve('resolved')
  })
  promise1.then(res => {
    console.log(res) // 输出:resolved,对应上面resolve出来的值
  })


  // 被reject的情况
  const promise2 = new Promise((resolve, reject) => {
    reject('rejected')
  })
  // 第一种捕获错误的方式:promise.catch
  promise2.then(res => {
    console.log(res) // 不会触发
  }).catch(err => {
    console.log(err) // 输出:rejected
  })

  // 第二种捕获错误的方式:then的第二个回调函数
  promise2.then(res => {
    console.log(res) // 不会触发
  }, err => {
    console.log(err) // 输出:rejected
  })

  // finally,最终的意思,就是不管是fulfilled还是rejected,都会触发,但无法接收到值
  promise1.finally((res) => {
    console.log('finally') // promise1是fulfilled状态,会触发
    console.log(res) // 输出undefined
  })
  promise2.finally((err) => {
    console.log('finally') // promise2是rejected状态,也会触发
    console.log(err) // 输出undefined
  })

then、catch回调函数的返回值

then返回值

  const promise = Promise.resolve(1)

  promise.then(res => {
    console.log(res) // 输出:1
    return 2
  }).then(res => {
    console.log(res) // 输出:2,就是上一个回调函数的返回值
  }).then(res => {
    console.log(res) // 输出:undefined,上一个回调函数没有返回值,所以是undefined
  })

  promise.then(res => {
    // 上面那个回调函数的返回值不会影响这个,只会影响后续的回调函数
    // 原因是因为then每次都是返回一个新的Promise对象
    console.log(res) // 输出:1
  })

catch返回值

  const promise = Promise.reject(1)
  promise.catch(err => {
    console.log(err) // 输出:1
    return 2
  }).catch(err => {
    console.log(err) // 不触发,因为被catch后,后续就不会走catch了,而是then
  }).then(res => {
    console.log(res) // 输出:2
  })

返回Promise对象

回调函数中如果返回的是Promise对象,后续的回调函数会等待Promise完成才会触发,且接收到的值也是返回的Promise的值,而不是这个Promise对象。

  const promise = Promise.resolve(1)
  promise.then(res => {
    console.log(res) // 输出: 1
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(2)
      }, 1000)
    })
  }).then(res => {
    console.log(res) // 1s后输出:2,而不是一个Promise对象
  })

回调函数返回的多层Promise都会被拉平

  const promise = Promise.resolve(1)
  promise.then(res => {
    console.log(res) // 输出: 1
    return new Promise(resolve => {
      setTimeout(() => {
        const promise3 = new Promise(resolve => {
          setTimeout(() => {
            resolve(2)
          }, 1000)
        })
        resolve(promise3)
      }, 1000)
    })
  }).then(res => {
    console.log(res) // 2s后输出:2,会等待2层Promise都完成
  })

如果非要返回一个Promise对象呢?返回的promise转换为别的数据结构

  const promise = Promise.resolve(1)
  promise.then(res => {
    console.log(res) // 输出: 1
    return {
      promise: Promise.resolve(666)
    }
  }).then(res => {
    console.log(res) // 输出:{ promise: Promise }
  })

触发catch的方式

触发catch方式有三种:

  • 第一种就是reject触发;
  • 第二种就是Promise构造函数中报错;
  • 第三种则是回调函数返回了一个rejected的Promise对象或者报错
  // 1
  const promise1 = new Promise((resolve, reject) => {
    reject('rejected')
  })
  promise1.catch(err => {
    console.log(err) // 输出:rejected
  })


  // 2
  const promise2 = new Promise((resolve, reject) => {
    throw 'throw rejected'
  })
  promise2.catch(err => {
    console.log(err) // 输出:throw rejected,报错同样会被catch
  })


  // 3.1
  const promise3 = new Promise((resolve, reject) => {
    resolve('resolved')
  })
  promise3.then(res => {
    console.log(res) // 输出:resolved
    // 通过Promise的静态方法:reject,返回一个被reject的Promise对象
    return Promise.reject('then rejected')
  }).catch(err => {
    console.log(err) // 输出:then rejected
  })

  // 3.2
  const promise4 = new Promise((resolve, reject) => {
    resolve('resolved')
  })
  promise4.then(res => {
    console.log(res) // 输出:resolved
    throw 'throw rejected' // 报错,会触发后面的catch
  }).catch(err => {
    console.log(err) // 输出:throw rejected
  })

两种捕获错误的区别

其实通过上文的示例,不知道的小伙伴,这会大概已经猜到了,如果通过then的第一个回调函数触发的reject,不会被then的第二个回调函数接收。

  const promise1 = new Promise((resolve, reject) => {
    resolve('resolved')
  })
  promise1.then(res => {
    console.log(res) // 输出:resolved
    // 通过Promise的静态方法:reject,返回一个被reject的Promise对象
    return Promise.reject('then rejected')
  }, err => {
    console.log(err) // 不会触发
  }).catch(err => {
    console.log(err) // 输出:then rejected
  })

  const promise2 = new Promise((resolve, reject) => {
    resolve('resolved')
  })
  promise2.then(res => {
    console.log(res) // 输出:resolved
    throw 'throw rejected' // 报错,会触发后面的catch
  }, err => {
    console.log(err) // 还是不会触发
  }).catch(err => {
    console.log(err) // 输出:throw rejected
  })

Promise的一些常用API

Promise.resolve

返回一个fulfilled的Promise对象

  const promise = Promise.resovle('fulfilled')

  promise.then(res => {
    console.log(res) // 输出:fulfilled
  })

Promise.reject

返回一个rejected的Promise对象

  const promise = Promise.reject('rejected')

  promise.catch(err => {
    console.log(err) // 输出:rejected
  })

Promise.all

接收一个Promise对象数组,生成一个新的Promise对象,只要有一个Promise对象rejected了,那么这个新的Promise的对象状态就变成了rejected;如果所有的都fulfilled了,那么这个新的Promise的对象状态就变成了fulfilled,then回调中可以接收到所有Promise返回值组成的数组。

  const promise1 = Promise.resolve(1)
  const promise2 = Promise.resolve(2)
  const promise3 = Promise.reject(3)

  Promise.all([
    promise1,
    promise2,
    promise3,
  ]).then(res => {
    console.log(res) // 不触发
  }).catch(err => {
    console.log(err) // 输出:3
  })

  Promise.all([
    promise1,
    promise2,
  ]).then(res => {
    console.log(res) // 输入:[1, 2]
  }).catch(err => {
    console.log(err) // 不触发
  })

Promise.allSettled

和Promise.all有点类似,是之后补充的一个新API;和all不同的是,它只会再所有Promise处理完成后(状态变成fullfilled或rejected)才会触发;只会触发then的第一个回调,接收到所有Promise的状态和值组成的数组。

  const promise1 = Promise.resolve(1)
  const promise2 = Promise.resolve(2)
  const promise3 = Promise.reject(3)

  Promise.allSettled([
    promise1,
    promise2,
    promise3,
  ]).then(res => {
    /**
     * 输出:
     *  [
     *    { status: 'fulfilled', value: 1 },
     *    { status: 'fulfilled', value: 2 },
     *    { status: 'rejected', reason: 3 },
     * ]
     */
    console.log(res)
  }).catch(err => {
    console.log(err)
  })

Promise.race

接收一个Promise对象数组,返回一个新的Promise对象,如果有一个Promise对象的状态率先改变,那么这个新的Promise对象的状态和值就是这个率先改变的Promise对象的状态和值。

  const promise1 = new Promise((resolve) => {
    setTimeout(() => {
      resolve(1)
    }, 100)
  })

  const promise2 = new Promise((resolve) => {
    setTimeout(() => {
      resolve(2)
    }, 200)
  })

  const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(3)
    }, 50)
  })

  Promise.race([
    promise1,
    promise2,
  ]).then(res => {
    console.log(res) // 输出:1
  }).catch(err => {
    console.log(err) // 不触发
  })

  Promise.race([
    promise1,
    promise2,
    promise3,
  ]).then(res => {
    console.log(res) // 不触发
  }).catch(err => {
    console.log(err) // 输出:3
  })

Promise.any

接收一个Promise对象数组,返回一个新的Promise对象,当有一个Promise对象变成fullfiled状态,那么新的Promise对象就变成fullfiled状态,如果所有Promise对象变成rejected状态,新的Promise对象才变成rejected状态。

  const promise1 = new Promise((resolve) => {
    setTimeout(() => {
      resolve(1)
    }, 100)
  })

  const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(2)
    }, 200)
  })

  const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(3)
    }, 50)
  })

  Promise.any([
    promise1,
    promise2,
  ]).then(res => {
    console.log(res) // 输出:1
  }).catch(err => {
    console.log(err) // 不触发
  })

  Promise.any([
    promise2,
    promise3,
  ]).then(res => {
    console.log(res) // 不触发
  }).catch(err => {
    // 这里接收到err是AggregateError实例
    // 输出:AggregateError: All promises were rejected
    console.log(err)
  })

全局捕获Promise的reject

在我们需要做错误监控时,通常都需要对未捕获的Promise做处理

  window.addEventListener('unhandledrejection', (event) => {
    const { promise, reason } = event
    console.log(promise) // 未捕获的Promise对象
    console.log(reason) // 原因,就是reject抛出来的内容

    // 上报错误
    reportError({
      reason,
      timestamp: Date.now()
    })

    // 阻止默认行为,可避免继续报错
    event.preventDefault()
  })

事件循环,宏任务和微任务

后续讲到的await和微任务有关,微任务又是事件循环的一部分,所以这里就先讲一下事件循环吧;这里讲的是浏览器的事件循环,Node的事件循环复杂很多,我就不讲啦(其实我也没搞明白)。

首先JS是单线程的,意味着所有的JS代码只会依次执行,遇到一些耗时的任务时,JS不能像其他多线程语言一样,可以另外开一个线程去执行,但JS也不能傻等吧,所以为了避免阻塞执行,就引入了事件循环机制,注意事件循环并不是JS的专属。

事件循环的机制大概是这样的,首先JS执行同步任务,当遇到异步任务,则会暂时将它添加到任务队列中,等到异步任务准备好了,会执行对应的回调,但需要等JS执行完本轮同步任务才会回过来头来处理这些回调,完成后,再执行下一轮,如此往复便是事件循环机制。

事件循环中的任务队列又分为宏任务和微任务;宏任务队列有多个,微任务队列只有一个;微任务是在宏任务中添加的;首先整个script标签创建了第一个宏任务队列,当遇到异步任务,如果是宏任务则会创建新的宏任务队列,如果是微任务,则会添加到微任务队列;如果新的宏任务队列中又有新的异步任务,那么就会像套娃一样,继续创建宏任务队列,添加微任务等等。

宏任务大概有这些:

  • script整体代码
  • setTimout
  • setInterval
  • setImmediate(node)
  • requestAnimationFrame

微任务大概有这些:

  • process.nextTick(node)
  • Promise
  • Object.observe
  • MutationObserver

一道恶心的题

我这里就不贴答案了,大家自行思考,答案和分析放在文章末尾。

  setTimeout(() => {
    console.log(1)
  })

  console.log(2)

  const promise = new Promise(resolve => {
    resolve(3)
    console.log(4)
  })

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

  function fn() {
    console.log(5)
  }

  async function asyncFn() {
    await fn()
    console.log(6)
    await promise
    console.log(7)
  }

  console.log(8)

  asyncFn().then(() => {
    console.log(9)
  })

  console.log(10)

搭配async和await

async和await是异步编程的终极解决方案,使得写异步代码就像写同步代码一样丝滑。

基本使用

  const promise1 = new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved 1')
    }, 1000)
  })

  const promise2 = new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved 2')
    }, 1000)
  })

  async function exec() {
    console.log('start')
    await promise1 // 等待promise1完成
    console.log('promise1 fulfilled') // 1s后输出
    const ret = promise2 // 等待promise2完成,接收了其resolve的值
    console.log('promise2 fulfilled') // 2s后输出
    console.log(`promise2 value: ${ret}`) // 输出resolve的值
  }
  exec()

捕获错误

  const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('rejected')
    }, 1000)
  })

  async function exec1() {
    console.log('start')
    await promise1 // 等待promise1完成
    console.log('promise1 fulfilled') // 不会输出
  }
  exec1() // 抛出错误,Uncaught (in promise) rejected

  async function exec2() {
    try {
      console.log('start')
      await promise1 // 等待promise1完成
      console.log('promise1 fulfilled') // 不会输出
    } catch(err) {
      console.log(err) // 捕获到reject,err即reject的内容: rejected
    }
  }
  exec2() // 不会抛出错误

await-to-js

可以看到使用await后,对错误处理还是挺麻烦的,这里推荐一个库:await-to-js,用法如下:

  import to from 'await-to-js';

  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('rejected')
    }, 1000)
  })

  async function exec() {
    const [err, res] = await to(promise)
    console.log(err) // 输出rejected
    console.log(res) // 输出undefined
  }
  exec()

内部源码也非常简单:

  function to (
    promise,
    errorExt
  ) {
    return promise
      .then((data) => [null, data])
      .catch((err) => {
        if (errorExt) {
          const parsedError = Object.assign({}, err, errorExt)
          return [parsedError, undefined]
        }
        return [err, undefined]
      })
  }

实例场景

接口超时

  const handleTimeout = (promise, timeout) => {
    return Promise.race([
      promise,
      new Promise((resolve, reject) => {
        setTimeout(() => {
          reject('请求超时')
        }, timeout)
      })
    ])
  }

  // 一分钟超时处理
  handleTimeout(
    ajax({
      url: 'xxx'
    }), 
    60 * 1000
  )

响应拦截

为了描述我要要演示什么,先给大家看一下axios的响应拦截器用法吧

  axios.interceptors.response.use(function (response) {
    return response.data
  })

相信大家都做过这样的操作吧,拦截响应,将响应值外面的data层去掉,那么这里面是如何实现的。

来吧,展示:

  // 模拟一个获取用户列表的接口
  const getUserList = () => {
    return Promise.resolve({
      data: [
        { name: 'ly', age: 18, id: 1 },
        { name: 'yl', age: 19, id: 2 },
      ]
    })
  }

  const responseInterceptor = (_promise) => {
    let promise = _promise
    const ret = {
      promise,
      addInterceptor(resolve, reject) {
        ret.promise = promise.then(resolve, reject)
      }
    }
    return ret
  }

  const requestInstance = responseInterceptor(getUserList())

  // 拦截,去除data外面的那一层
  requestInstance.addInterceptor(res => {
    return res.data
  })

  requestInstance.promise.then(res => {
    /* 
      输出:
        [
          { name: 'ly', age: 18, id: 1 },
          { name: 'yl', age: 19, id: 2 },
        ]
    */
    console.log(res)
  })

  requestInstance.addInterceptor(res => {
    return '你是大傻逼'
  })

  requestInstance.promise.then(res => {
    // 输出:'你是大傻逼'
    console.log(res)
  })

拦截器还有很多其他用处,如:将code非200的情况转为rejected的Promise对象,以方便使用。

串行请求

  • 方法1(await)
  const getUserList = () => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve([
          { name: 'ly', age: 18, id: 1 },
          { name: 'yl', age: 19, id: 2 },
        ])
      }, 500)
    }).then(res => {
      console.log(res)
    })
  }

  const getOrgList = () => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve([
          { orgName: '友谊的小船', id: 1 },
          { orgName: '五黑小分队', id: 2 },
        ])
      }, 500)
    }).then(res => {
      console.log(res)
    })
  }

  const tasks = [getUserList, getOrgList]

  async function exec() {
    for(const task of tasks) {
      await task()
    }
    console.log('all task completed')
  }

  exec()
  • 方法2(反复赋值promise)
  const getUserList = () => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve([
          { name: 'ly', age: 18, id: 1 },
          { name: 'yl', age: 19, id: 2 },
        ])
      }, 500)
    }).then(res => {
      console.log(res)
    })
  }

  const getOrgList = () => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve([
          { orgName: '友谊的小船', id: 1 },
          { orgName: '五黑小分队', id: 2 },
        ])
      }, 500)
    }).then(res => {
      console.log(res)
    })
  }

  const tasks = [getUserList, getOrgList]

  let promise = tasks.shift()()

  tasks.forEach(task => {
    promise = promise.then(() => task())
  })

  promise.then(() => {
    console.log('all task completed')
  })

并行请求

讲了串行,并行不是简简单单吗,就是Promise.all和Promise.allSettled的应用,这里就不重复讲了,上文已提到。

源码实现

  • 首先定义三个状态,写出构造函数
class MyPromise {
  static PENDING = 'pending'
  static FULFILLED = 'fulfilled'
  static REJECTED = 'rejected'
  constructor(exec) {
    this.state = MyPromise.PENDING // 初始为pending状态
    this.result = null // promise的结果

    // 同步执行exec,传递两个回调函数,注意绑定this(不明白的小朋友们去补习下js基础哦)
    exec(this.resolve.bind(this), this.reject.bind(this))
  }
}
  • 初步实现resolve和reject
class MyPromise {
  resolve(result) {
    // 添加判断,保证状态不可变,Promise可是一个有原则的类
    if (this.state === MyPromise.PENDING) {
      this.result = result;
      this.state = MyPromise.FULFILLED;
    }
  }
  reject(result) {
    // 同上,保证状态不可变
    if (this.state === MyPromise.PENDING) {
      this.result = result;
      this.state = MyPromise.REJECTED;
    }
  }
}
  • 重头戏!实现then,完善resolve、reject
class MyPromise {
  constructor() {
    ...
    // 增加两个回调函数存储器
    this.fulfilledCallbacks = [];
    this.rejectedCallbacks = [];
  }
  resolve(result) {
    if (this.state === MyPromise.PENDING) {
      // 因为promise.then是异步的,所以用setTimeout模拟一下,但注意并不是微任务
      setTimeout(() => {
        this.result = result;
        this.state = MyPromise.FULFILLED;
        // 执行所有的fulfilledCallback
        this.fulfilledCallbacks.forEach(callback => callback(this.result));
      })
    }
  }

  reject(result) {
    if (this.state === MyPromise.PENDING) {
      setTimeout(() => {
        this.result = result;
        this.state = MyPromise.REJECTED;
        // 执行所有的rejectedCallback
        this.rejectedCallbacks.forEach(callback => callback(this.result));
      })
    }
  }

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

    if (this.state === MyPromise.FULFILLED) {
      // 如果此时已经为fulfilled,则立即执行onFulfilled回调
      setTimeout(() => {
        onFulfilled(this.result);
      })
    } else if (this.state === MyPromise.REJECTED) {
      // 如果此时已经为rejected,则立即执行onRejected回调
      setTimeout(() => {
        onRejected(this.result)
      })
    } else if (this.state === MyPromise.PENDING) {
      // pending中,则暂存到数组中
      this.fulfilledCallbacks.push(() => {
        onFulfilled(this.result)
      })
      this.rejectedCallbacks.push(() => {
        onRejected(this.result)
      })
    }
  }
}

到这里一个非常简陋的Promise就实现了,但还缺少了很多功能,后面继续完善,加油。

  • 完善then,实现链式调用、值传递
class MyPromise {
  then(onFulfilled, onRejected) {
    onFulfilled = typeof (onFulfilled) === 'function' ? onFulfilled : value => value;
    onRejected = typeof (onRejected) === 'function' ? onRejected : reason => { throw reason };

    const promise = new MyPromise((resolve, reject) => {
      // 如果此时已经为fulfilled,则立即执行success回调
      if (this.state === MyPromise.FULFILLED) {
        setTimeout(() => {
          try {
            const res = onFulfilled(this.result);
            resolve(res);
          } catch (err) {
            reject(err);
          }
        })
      } else if (this.state === MyPromise.REJECTED) {
        // 如果此时已经为rejected,则立即执行fail回调
        setTimeout(() => {
          try {
            const res = onRejected(this.result);
            reject(res);
          } catch (err) {
            reject(err);
          }
        })
      } else if (this.state === MyPromise.PENDING) {
        this.fulfilledCallbacks.push(() => {
          try {
            const res = onFulfilled(this.result);
            resolve(res);
          } catch (err) {
            reject(err);
          }
        });
        this.rejectedCallbacks.push(() => {
          try {
            const res = onRejected(this.result);
            reject(res);
          } catch (err) {
            reject(err);
          }
        });
      }
    })
    return promise;
  }
}
  • 继续完善then,解析回调函数返回的Promise
class MyPromise {
  then(onFulfilled, onRejected) {
    onFulfilled = typeof (onFulfilled) === 'function' ? onFulfilled : value => value;
    onRejected = typeof (onRejected) === 'function' ? onRejected : reason => { throw reason };

    const promise = new MyPromise((resolve, reject) => {
      // 如果此时已经为fulfilled,则立即执行success回调
      if (this.state === MyPromise.FULFILLED) {
        setTimeout(() => {
          try {
            const res = onFulfilled(this.result);
            MyPromise.resolvePromise(promise, res, resolve, reject);
            return;
            if (res instanceof MyPromise) {
              res.then(resolve, reject);
            } else {
              resolve(res);
            }
          } catch (err) {
            reject(err);
          }
        })
      } else if (this.state === MyPromise.REJECTED) {
        // 如果此时已经为rejected,则立即执行fail回调
        setTimeout(() => {
          try {
            const res = onRejected(this.result);
            MyPromise.resolvePromise(promise, res, resolve, reject);
            return;
            if (res instanceof MyPromise) {
              res.then(resolve, reject);
            } else {
              reject(res);
            }
          } catch (err) {
            reject(err);
          }
        })
      } else if (this.state === MyPromise.PENDING) {
        this.fulfilledCallbacks.push(() => {
          try {
            const res = onFulfilled(this.result);
            MyPromise.resolvePromise(promise, res, resolve, reject);
            return;
            if (res instanceof MyPromise) {
              res.then(resolve, reject);
            } else {
              resolve(res);
            }
          } catch (err) {
            reject(err);
          }
        });
        this.rejectedCallbacks.push(() => {
          try {
            const res = onRejected(this.result);
            MyPromise.resolvePromise(promise, res, resolve, reject);
            return;
            if (res instanceof MyPromise) {
              res.then(resolve, reject);
            } else {
              reject(res);
            }
          } catch (err) {
            reject(err);
          }
        });
      }
    })
    return promise;
  }

  static resolvePromise(promise, retVal, resolve, reject) {
    if (retVal instanceof MyPromise) {
      if (retVal.state === MyPromise.PENDING) {
        retVal.then(res => {
          // 递归,不管resolve中套了多少层的promise都给解析出来
          MyPromise.resolvePromise(promise, res, resolve, reject)
        }, reject);
      } else if (retVal.state === MyPromise.FULFILLED) {
        resolve(retVal.result);
      } else if (retVal.state === MyPromise.REJECTED) {
        reject(retVal.result);
      }
    } else {
      return resolve(retVal);
    }
  }
}

收工,then函数已经完成,咱这个盗版基本上正版差不多了。

再完善亿点点细节,完整源码奉上:

  • catch实际上就是调用了then;
  • finally就是调用then,然后两个回调函数都调用finally的回调;
  • 静态resolve、reject就是创建一个Promise对象,然后立马调用resolve或reject;
 class MyPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
    constructor(exec) {
      this.fulfilledCallbacks = [];
      this.rejectedCallbacks = [];
      this.state = MyPromise.PENDING;
      this.result = null;
      try {
        exec(this.resolve.bind(this), this.reject.bind(this));
      } catch (err) {
        this.reject(err);
      }
    }

    static resolve(result) {
      return new MyPromise((resolve) => {
        resolve(result);
      })
    }

    static reject(result) {
      return new MyPromise((resolve, reject) => {
        reject(result);
      })
    }

    resolve(result) {
      // 保持state不可逆
      if (this.state === MyPromise.PENDING) {
        setTimeout(() => {
          this.result = result;
          this.state = MyPromise.FULFILLED;
          // 执行所有的successCallback
          this.fulfilledCallbacks.forEach(callback => callback(this.result));
        })
      }
    }

    reject(result) {
      // 保持state不可逆
      if (this.state === MyPromise.PENDING) {
        setTimeout(() => {
          this.result = result;
          this.state = MyPromise.REJECTED;
          // 执行所有的failCallback
          this.rejectedCallbacks.forEach(callback => callback(this.result));
        })
      }
    }

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

      const promise = new MyPromise((resolve, reject) => {
        // 如果此时已经为fulfilled,则立即执行success回调
        if (this.state === MyPromise.FULFILLED) {
          setTimeout(() => {
            try {
              const res = onFulfilled(this.result);
              MyPromise.resolvePromise(promise, res, resolve, reject);
              return;
              if (res instanceof MyPromise) {
                res.then(resolve, reject);
              } else {
                resolve(res);
              }
            } catch (err) {
              reject(err);
            }
          })
        } else if (this.state === MyPromise.REJECTED) {
          // 如果此时已经为rejected,则立即执行fail回调
          setTimeout(() => {
            try {
              const res = onRejected(this.result);
              MyPromise.resolvePromise(promise, res, resolve, reject);
              return;
              if (res instanceof MyPromise) {
                res.then(resolve, reject);
              } else {
                reject(res);
              }
            } catch (err) {
              reject(err);
            }
          })
        } else if (this.state === MyPromise.PENDING) {
          this.fulfilledCallbacks.push(() => {
            try {
              const res = onFulfilled(this.result);
              MyPromise.resolvePromise(promise, res, resolve, reject);
              return;
              if (res instanceof MyPromise) {
                res.then(resolve, reject);
              } else {
                resolve(res);
              }
            } catch (err) {
              reject(err);
            }
          });
          this.rejectedCallbacks.push(() => {
            try {
              const res = onRejected(this.result);
              MyPromise.resolvePromise(promise, res, resolve, reject);
              return;
              if (res instanceof MyPromise) {
                res.then(resolve, reject);
              } else {
                reject(res);
              }
            } catch (err) {
              reject(err);
            }
          });
        }
      })
      return promise;
    }

    catch(onRejected) {
      return this.then(null, onRejected);
    }

    finally(callback) {
      const P = this.constructor;
      return this.then(
        value => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason }),
      )
    }

    static resolvePromise(promise, retVal, resolve, reject) {
      if (retVal instanceof MyPromise) {
        if (retVal.state === MyPromise.PENDING) {
          retVal.then(res => {
            // 递归,不管resolve中套了多少层的promise都给解析出来
            MyPromise.resolvePromise(promise, res, resolve, reject)
          }, reject);
        } else if (retVal.state === MyPromise.FULFILLED) {
          resolve(retVal.result);
        } else if (retVal.state === MyPromise.REJECTED) {
          reject(retVal.result);
        }
      } else {
        return resolve(retVal);
      }
    }
  }

最后再来点饭后甜点:实现all、allSettled、race

Promise.all

  MyPromise.all = function (promises) {
    return new Promise((resolve, reject) => {
      const result = []
      let fulfilledCount = 0
      promises.forEach((promise, index) => {
        promise.then(res => {
          result[index] = res
          fulfilledCount ++
          if(fulfilledCount === promises.length) {
            resolve(result)
          }
        }, err => {
          reject(err)
        })
      })
    })
  }

Promise.allSettled

  MyPromise.allSettled = function (promises) {
    return new Promise((resolve, reject) => {
      const result = []
      let completedCount = 0
      const callback = (value, index) => {
        result[index] = value
        completedCount ++
        if(completedCount === promises.length) {
          resolve(result)
        }
      }
      promises.forEach((promise, index) => {
        promise.then(res => {
          callback({
            status: 'fulfilled',
            value: res
          }, index)
        }, err => {
          callback({
            status: 'rejected',
            reson: err
          }, index)
        })
      })
    })
  }

Promise.race

  MyPromise.race = function (promises) {
    return new Promise((resolve, reject) => {
      promises.forEach((promise, index) => {
        promise.then(resolve, reject)
      })
    })
  }

事件循环题目解析

首先公布下答案:2 4 8 5 10 3 6 7 9 1

  1. 首先遇到setTimeout,是一个宏任务,不管它,继续,输出一个2;
  2. 继续,创建了一个Promise对象,resolve(3)不管它,继续,输出了一个4,因为Promise构造函数接收的回调函数是被同步执行的,那么第二个输出的就是它了(4);
  3. 继续,监听了promise的回调,不管它;
  4. 继续,声明了一个同步函数:fn,不管它;
  5. 继续,声明了一个异步函数:asyncFn,不管它;
  6. 继续,输出了8,那么第三个就是它了(8),没毛病吧,坚持住;
  7. 继续,执行了asyncFn,并且监听了回调,asyncFn中写了句:await fn(),尽管左边有个await,但await右边仍然是会被同步执行的,所以第四个就是fn中输出的5;
  8. 继续,注意,第五个可不是紧随其后的输出6,而是10,因为await会形成一个微任务,所以会等之前的同步任务执行完成;
  9. 继续,第六个输出的是3,而不是6,因为promise的回调监听是在await fn()之前执行的;
  10. 继续,输出6,没什么异议吧;
  11. 继续,输出7,再输出9,没异议吧;
  12. 继续,都执行完了,setTimeout:是不是该想起我了?最后输出1。

完结🎉,感谢收看。

大佬,赏点赞吧.jpg