Promise的秘密

8次阅读

共计 15808 个字符,预计需要花费 40 分钟才能阅读完成。

写在前面

本篇文章将会带大家从分解 promise 入手,一步步实现一个 promise。但阅读之前需要比较熟练地了解了解用法,结合用法看文章可能更容易理解。

结构

先看一下简单的用法。

const promise = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')
   })
})
.then(value => { ...}, reason => {...})
.catch(error => { ...})

Promise 的构造函数接收了一个回调,这个回调就是下面要讲到的执行器,执行器的参数 resolve, reject 也是两个函数,
负责改变 promise 实例的状态和它的值,then 函数中的回调在状态改变后执行。

注意:不是 then 函数在状态改变后执行,而是 then 中的回调函数在状态改变后执行。then 方法会将其中的回调放入执行队列,promise 的状态改变后再将队列中的函数一一执行

如果要实现一个最简单的 promise 类,内部结构都要包含什么呢?

  • 状态:fulfiled、rejected、pending
  • 值:promise 的值
  • 执行器:提供改变 promise 状态的入口
  • resolve 和 reject 方法:前者将 promise 改变为 fulfiled,后者将其改变为 rejected。可以在执行器内根据实际业务来控制是 resolve 或 reject。
  • then 方法:接收两个回调,onFulfilled, onRejected。分别在 promise 状态变为 fulfiled 或 rejected 后执行,这里涉及到将回调注册进两个执

行队列的操作,后文会讲到

const PENDING = 'pending'
const FULFILLED = 'fulfiled'
const REJECTED = 'rejected'

class NewPromise {constructor(handler) {
    this.state = PENDING
    this.value = undefined
    this.successCallback = []
    this.failureCallback = []
    try {handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {this.reject(e)
    }
  }

  // resolve 和 reject 方法
  resolve(value) {...}
  reject(reason) {...}

  // then 方法
  then(onFulfilled, onRejected) {...}
}

结构中的每个部分是如何实现的呢?

Promise 的执行器

执行器是我们初始化 promise 时候传入的回调,是我们操作 promise 的入口,所以执行器的实现不复杂,也就是将我们传入的回调执行一下。

class NewPromise {
  ...
  handler(resolve.bind(this), reject.bind(this))
  ...
}

实际上,执行器会接受两个回调,resolve 和 reject。它们真正起到改变 promise 状态的作用。

resolve 和 reject

实际上是两个函数,所做的事情不复杂。

  • 改变 promise 的状态
  • 将接收的值作为 promise 的 value
  • 依次执行 then 中注册的回调
const PENDING = 'pending'
const FULFILLED = 'fulfiled'
const REJECTED = 'rejected'

class NewPromise {constructor(handler) {
    this.state = PENDING
    this.value = undefined

    // 两个队列,后面会讲到
    this.successCallback = []
    this.failureCallback = []
    try {
      // 执行器,由于 resolve 和 reject 中用到了 this,这里需要 bind 一下
      handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {this.reject(e)
    }
  }

  resolve(value) {if (this.state !== PENDING) return
    this.state = FULFILLED
    this.value = value
    // 用 setTimeout 模拟异步方式
    setTimeout(() => {
      this.successCallback.forEach(item => {item(value)
      })
    })
  }

  reject(reason) {if (this.state !== PENDING) return
    this.state = REJECTED
    this.value = reason
    setTimeout(() => {
      this.failureCallback.forEach(item => {setTimeout(item(reason))
      })
    })
  }
}

看一下它们的实现,改变状态、赋值 value,最重要的一点:循环执行 then 方法注册到队列中的回调。

而规范中要求回调以异步方式执行,保证在执行所有的回调之前,所有回调已经通过 then 注册完成,所以这里用 setTimeout 模拟了一下。

then 方法:

(翻译整理自 Promise/A+ 规范)
promise 必须提供 then 方法来访问这个 promise 当前或者最终的值
then 方法有两个参数:onFulfilled, onRejected,都是可选的。关于这两个参数,这里有几个规则:

onFulfilled, onRejected 都不是函数的时候,必须被忽略

实际上忽略的意思也就是如果不是函数,默认给它赋值成函数,返回值为 then 所属的 promise 的值。这样是做是为了在 then()函数未传回调的时候,可以将 promise 的值传递下去。场景如下:

promise(resolve => resolve('success'))
    .then()
    .then(function(value) {console.log(value)
    })

具体实现上,在它不是函数的时候可以给它赋值一个默认函数,也可以直接调用新返回的 promise 中的 resolve 或 reject 将值传下去,来达到忽略的效果

onFulfilled 是函数的时候

  • 必须在当前的 promise 的状态变为 fulfilled 的时候被调用,promise 被 resolve 的值也就是它的第一个参数
  • 不能在 fulfilled 之前被调用
  • 最多只能被调用一次

onRejected 是函数的时候

  • 必须在当前的 promise 的状态变为 rejected 的时候被调用,promise 被 reject 的值也就是它的第一个参数。不能在 rejected 之前被调用,
  • 最多只能被调用一次。

then 可能会被调用多次

  • 当 promise 状态变为 fulfilled,所有 onFulfilled 将会按照最开始在 then 方法中注册的顺序去调用
  • 当 promise 状态变为 rejected,所有 onRejected 将会按照最开始在 then 方法中注册的顺序去调用

就像下边这样:

  const promise = new Promise((resolve, reject) => {setTimeout(() => resolve('success'))
  })
  promise.then(res => {console.log(res, '第一次');
  })
  promise.then(res => {console.log(res, '第二次');
  })

鉴于这种情况,需要在我们实现的 promise 内部维护两个队列,队列中的元素是 then 方法内注册的回调函数(onFulfilled, onRejected),每调用一次 then,就向队列中注册一个回调,它们会在 promise 状态改变时被依次执行。

返回一个 promise,便于链式调用

 promise2 = promise1.then(onFulfilled, onRejected);

then 返回的 promise(也就是 promise2)的状态,取决于其回调函数(onFulfilled 或 onRejected)的返回值或者 promise1 的状态,具体表现为:

  • onFulfilled 或 onRejected 的返回值是一个值 x,那么 promise2 的状态为 resolve,值为 x
  • 如果 onFulfilled 或 onRejected 执行出错,并抛出了错误对象 e,那么 promise2 的状态为 rejected,值为这个错误对象 e
  • 如果 onFulfilled 不是一个函数,但 promise1 状态变为 fulfilled,那么 promise2 状态也为 fulfilled,值与 promise1 相同
  • 如果 onRejected 不是一个函数,但 promise1 状态变为 rejected,那么 promise2 状态也为 rejected,值与 promise1 相同(这个值是作为 promise2 的 reason)

实现

上面我们认识了 then 方法,结合定义和平时的用法可以猜测出我们自己实现的 promise 内的 then 方法需要做下边几件事:

  • 返回一个新的 promise 实例
  • then 所属的 Promise 在 pending 状态,将 then 的回调(onFulfilled, onRejected)分别放入执行队列等待执行,而这两个队列内的函数只有在 then 所属的

promise 状态被改变的时候执行。保证了规范中的 onFulfilled, onRejected 的执行时机。

  • then 所属的 Promise 状态不为 pending 时,执行队列中的回调开始依次执行,然后根据已经改变的状态以及回调的返回值来决定新的 promise 的状态

    • 举例来说:
    const promise1 = new Promise((resolve, reject) =>{...})
    const promise2 = promise1.then(value => {return 'success'}, reason => {return 'failed'})
假设 promise1 被 resolve 了,由于 then 中传入了代表 onFulfilled 的回调并且返回值为 success,那么 promise2 会被 resolve,值为 success。假设 promise2 被 reject 了,由于 then 中传入了代表 onRejected 的回调并且返回值为 failed,那么 promise2 会被 reject,reason 是 failed

下面一步步来实现 then 方法,先上结构:

class NewPromise {constructor(handler) {
    this.state = PENDING
    this.value = undefined

    // 两个队列,存放 onFulfiled 和 onRejected
    this.successCallback = []
    this.failureCallback = []
    try {handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {this.reject(e)
    }
  }
  then(onFulfilled, onRejected) {return new NewPromise((resolveNext, rejectNext) => {
      // pengding 状态向队列中注册回调
      if (state === PENDING) {successCallback.push(onFulfilled)
        failureCallback.push(onRejected)
      }

      // 要保证在当前 promise 状态改变之后,再去通过 resolveNext 或者 rejectNext 改变新的 promise 的状态
      if (state === FULFILLED) {resolveNext(value)
      }
      if (state === REJECTED) {rejectNext(value)
      }
    })
  }
}

上面的结构基本实现了 then 函数的大概逻辑,但是没有实现根据 onFulfilled, onRejected 两个回调的执行结果来决定新的 promise 的状态的效果,
只是将他们分别放到了各自的执行队列中去。

最终 then 返回的 promise 的状态和 onFulfilled, onRejected 的执行结果有关。我根据规范和实际情况整理了一张图:

然后让我们用代码来实现它(单以 onFulfilled 的执行情况举例)

    try {
      // 正常情况
      if (typeof onFulfilled !== 'function') {
        // 不是函数,直接忽略,将 then 所属的 promise 作为 then 返回的 promise 的值 resolve 来做到值的传递
        resolveNext(value)
      } else {
        // 获取 then 函数回调的执行结果
        const res = onFulfilled(value)
        if (res instanceof NewPromise) {
          // 当执行结果返回的是一个 promise 实例,等待这个 promise 状态改变后再改变 then 返回的 promise 的状态
          res.then(resolveNext, rejectNext)
        } else {
          // 当返回值是普通值,将其作为新 promise 的值 resolve
          resolveNext(res)
        }
      }
    } catch (e) {
      // 出现异常,新 promise 的状态变为 rejected,reason 就是错误对象
      rejectNext(e)
    }

整个这一部分,需要放入队列中等待 then 所属的 promise 状态改变再执行,从而改变 then 返回的 promise 的状态。
所以,我们需要将这一块包装起来。整合起来就是:

class NewPromise {constructor(handler) {
    this.state = PENDING
    this.value = undefined

    // 两个队列,存放 onFulfiled 和 onRejected
    this.successCallback = []
    this.failureCallback = []
    try {handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {this.reject(e)
    }
  }
  then(onFulfilled, onRejected) {const { state, value} = this
    return new NewPromise((resolveNext, rejectNext) => {
      const resolveNewPromise = value => {
        try {
          // 正常情况
          if (typeof onFulfilled !== 'function') {
            // 不是函数,直接忽略,将 then 所属的 promise 作为 then 返回的 promise 的值 resolve 来做到值的传递
            resolveNext(value)
          } else {
            // 获取 then 函数回调的执行结果
            const res = onFulfilled(value)
            if (res instanceof NewPromise) {
              // 当执行结果返回的是一个 promise 实例,等待这个 promise 状态改变后再改变 then 返回的 promise 的状态
              res.then(resolveNext, rejectNext)
            } else {
              // 当返回值是普通值,将其作为新 promise 的值 resolve
              resolveNext(res)
            }
          }
        } catch (e) {
          // 出现异常,新 promise 的状态变为 rejected,reason 就是错误对象
          rejectNext(e)
        }
      }
      const rejectNewPromise = reason => {
        try {
          // 正常情况
          if (typeof onRejected !== 'function') {
            // 不是函数,直接忽略,将 then 所属的 promise 作为 then 返回的 promise 的值 reject 来做到值的传递
            rejectNext(reason)
          } else {
            // 获取 then 函数回调的执行结果
            const res = onRejected(reason)
            if (res instanceof NewPromise) {
              // 当执行结果返回的是一个 promise 实例,等待这个 promise 状态改变后再改变 then 返回的 promise 的状态
              res.then(resolveNext, rejectNext)
            } else {
              // 当返回值是普通值,将其作为新 promise 的值 reject
              rejectNext(res)
            }
          }
        } catch (e) {
          // 出现异常,新 promise 的状态变为 rejected,reason 就是错误对象
          rejectNext(e)
        }
      }
      if (state === PENDING) {this.successCallback.push(resolveNewPromise)
        this.failureCallback.push(rejectNewPromise)
      }
      // 要保证在当前 promise 状态改变之后,再去改变新的 promise 的状态
      if (state === FULFILLED) {resolveNewPromise(value)
      }
      if (state === REJECTED) {rejectNewPromise(value)
      }
    })
  }
}

我们在自己的实现中是定义了两个数组作为任务队列存放 then 注册的回调,而实际的 promise 中,
then 方法是将回调注册到微任务队列中。等到 promise 状态改变,执行微任务队列中的任务。微任务在概念上可以认为是异步任务,这也印证了规范中 then 的回调必须
异步执行的说法。关于事件循环的一些知识点,我总结过一篇文章,今天,我明白了 JS 事件循环机制

catch 函数

catch 函数是用来处理异常的,当 promise 状态变为 rejected 的时候,捕获到错误原因。那么假设不用 catch,也可以在 then 函数的第二个回调中捕获这个错误。
而且 catch 返回的是一个 promise,所以与调用 Promise.prototype.then(undefined, onRejected)的行为是一样的

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

resolve 方法

Promise.resolve(value)返回的是一个 promise 对象,用于将传入的值 value 包装为 promise 对象。

那这样做有什么意义呢?实际上 value 可能是一个不确定的值,可能是 promise 也可能不是,没准可以调用 then 方法,也没准不可以。但是可以通过 resolve 方法将行为统一
起来。

const promise = function() {if (shouldBePromise) {return new Promise(function(resolve, reject) {resolve('ok')
    })
  }
  return 'ok'
}
promise().then(() => {...})

promise 返回的结果取决于 shouldBePromise,假设 shouldBePromise 为 false,那么 promise 就返回了字符串 ok,下边就不能调用 then 方法。
这个时候可以用 Promise().resolve 包起来,这样 promise 返回的始终是一个 promise 实例,保证了 then 方法的顺利调用。

Promise.resolve(promise()).then(() => {...})

总结一下特点:Promise.resolve 的参数如果:

  • 不传,返回一个 resolved 状态的 Promise
  • 是一个 thenable 对象(即带有 ”then” 方法),返回的 Promise 的状态将在这个对象状态改变时改变,并且与该对象的状态保持一致
  • 是普通值,返回一个 resolved 状态的 Promise,该 promise 的值为这个普通值
  • 是一个 Promise 对象,返回这个对象
  static resolve(value) {
    // value 不存在,直接返回一个 resolved 状态的 promise
    if (!value) {return new NewPromise(function (resolve) {resolve()
      })
    }
    // value 是 promise 实例,直接返回
    // 在这里需要首先判断是否是 promise 实例,再进行下边的判断
    // 因为我们自己构造的 promise 也是是 object,也有 then 方法
    if (value instanceof NewPromise) {return value}
    // 是 thenable 对象,返回的新的 promise 实例需要在 value 状态改变后再改变,且状态跟随 value 的状态
    if (typeof value === 'object' && typeof value.then === 'function') {return new NewPromise((resolve, reject) => {value.then(resolve, reject)
      })
    }
    // value 是普通值,返回新的 promise 并 resolve 这个普通值
    return new NewPromise(resolve => {resolve(value)
    })
  }

reject 方法

reject 方法对比 resolve 相对简单,它总是返回一个 reject 的 promise 对象,reject 的原因是我们传入的 reason

  static reject(reason) {return new NewPromise((resolve, reject) => {reject(reason)
    })
  }

finally 方法

返回的是一个 promise,作用是在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行回调函数。返回的新 promise 的状态和值取决于原来的 promise。

finally(callback) {
  // 返回值是 promise 对象,回调在 then 中执行,也就符合了 promise 结束后调用的原则
  return this.then(
    // then 方法的 onFulfiled 和 onRejected 都会被传入,保证无论 resolved 或 rejected 都会被执行

    // 获取到 promise 执行成功的结果,将这个结果作为返回的新 promise 的值
    res => NewPromise.resolve(callback())
        .then(() => {return res}),
    // 获取执行失败的结果。原理同上
    error => NewPromise.resolve(callback())
        .then(() => {throw error})
  )
}

all 方法

Promise.all(param) 接收一个参数数组,返回一个新的 promise 实例。当参数数组内的 promise 都 resolve 后或者参数内的实例执行完毕后,新返回的 promise 才会 resolve。
数组内任何一个 promise 失败(rejected),新返回的 promise 失败,失败原因就是第一个失败的 promise 的结果。

const p1 = Promise.resolve(1),
coint p2 = Promise.resolve(2),
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {console.log(results);  // [1, 2, 3]
});

由此可知,all 方法需要返回一个新的 promise 实例,然后根据接收的参数数组执行情况,控制新的 promise 实例的状态与值

  static all(instanceList) {return new NewPromise((resolve, reject) => {
      // 定义存放结果的数组
      const results = []
      let count = 0
      if (instanceList.length === 0) {resolve(results)
        return
      }
      instanceList.forEach((item, index) => {
        // 由于实例列表中的每个元素可能是各种各样的,所以要用 this.resolve 方法包装一层
        this.resolve(item).then(res => {results[index] = res
          count++
          // 当都执行完,resolve 新返回的 promise
          if (count === instanceList.length) {resolve(results)
          }
        }, error => {
          // 一旦有一个出错,就 reject 新返回的 promise
          reject(error)
        })
      })
    })
  }

实现之后可以清楚的看到,all 方法会并行执行所有 promise,结果按传入的 promise 数组的顺序输出。这让我想起了以前面试碰到的一个题目:
并发所有请求,按顺序输出。可以用 Promise.all 实现。但实际上会有请求失败的情况,所以更好的方式是下边要讲到的 Promise.allSettled。

allSettled 方法

如果说 finally 提供了在单个 promise 是否成功都需要执行代码提供了一种方式,那么 allSettled 就是为多个 promise 是否成功的场景提供了同样的操作方式。

Promise.allSettled()方法返回一个 promise,该 promise 在所有给定的 promise 已被解析或被拒绝后解析,并且每个对象都描述每个 promise 的结果。

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));
// expected output:
// "fulfilled"
// "rejected"

不同于 Promise.all 的一旦有一个执行失败,就无法获得所有 promise 都执行完成的时间点的特点。无论某个 promise 成功与否,一旦所有的 promise 都完成,
就可以获得这个时间点。因为其返回的新的 promise,总是被 resolve 的,并且值是所有 promise 执行结果的描述。

[{"status":"rejected","reason":"失败"},
  {"status":"fulfiled","value":"成功"}
]

要实现它,需要在每个 promise 执行的时候把结果记录下来放进一个数组内,最后在所有 promise 执行完成后,resolve 结果数组,改变返回的新的 promise 的状态。

  static allSettled(instanceList) {return new NewPromise((resolve, reject) => {const results = []
      let count = 0
      if (instanceList.length === 0) {resolve([])
        return
      }
      // 定义一个函数,来生成结果数组
      const generateResult = (result, i) => {
        count++
        results[i] = result
        // 一旦全部执行完成,resolve 新返回的 promise
        if (count === instanceList.length) {resolve(results)
        }
      }
      instanceList.forEach((item, index) => {
        // 在每个 promise 完成后将状态记录到结果数组中
        this.resolve(item).then(
          value => {
            generateResult({
              status: FULFILLED,
              value
            }, index)
          },
          reason => {
            generateResult({
              status: REJECTED,
              reason
            }, index)
          }
        )
      })
    })
  }

race 方法

与 all 方法类似,接受一个实例数组为参数,返回新的 promise。但区别是一旦实例数组中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。

  static race(instanceList) {return new NewPromise((resolve, reject) => {if (instanceList.length === 0) {resolve([])
        return
      }
      instanceList.forEach(item => {
        // 由于实例列表中的每个元素可能是各种各样的,所以要用 this.resolve 方法包装一层
        this.resolve(item).then(res => {
          // 一旦有一个 resolve 了,那么新返回的 promise 状态就被 resolve
          resolve(res)
        }, error => {reject(error)
        })
      })
    })
  }

完整代码

到此为止就实现了一个相对完整的 promise,代码如下:

class NewPromise {constructor(handler) {
    this.state = PENDING
    this.value = undefined
    this.successCallback = []
    this.failureCallback = []
    try {handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {
      // 执行器出现错误需要 reject
      this.reject(e)
    }
  }

  resolve(value) {if (this.state !== PENDING) return
    this.state = FULFILLED
    this.value = value
    // 规范中要求 then 中注册的回调以异步方式执行,保证在 resolve 执行所有的回调之前,// 所有回调已经通过 then 注册完成
    setTimeout(() => {
      this.successCallback.forEach(item => {item(value)
      })
    })
  }
  reject(reason) {if (this.state !== PENDING) return
    this.state = REJECTED
    this.value = reason
    setTimeout(() => {
      this.failureCallback.forEach(item => {item(reason)
      })
    })
  }
  then(onFulfilled, onRejected) {const { state, value} = this
    return new NewPromise((resolveNext, rejectNext) => {
      const resolveNewPromise = value => {
        try {
          // 正常情况
          if (typeof onFulfilled !== 'function') {
            // 不是函数,直接忽略,将 then 所属的 promise 作为 then 返回的 promise 的值 resolve 来做到值的传递
            resolveNext(value)
          } else {
            // 获取 then 函数回调的执行结果
            const res = onFulfilled(value)
            if (res instanceof NewPromise) {
              // 当执行结果返回的是一个 promise 实例,等待这个 promise 状态改变后再改变 then 返回的 promise 的状态
              res.then(resolveNext, rejectNext)
            } else {
              // 当返回值是普通值,将其作为新 promise 的值 resolve
              resolveNext(res)
            }
          }
        } catch (e) {
          // 出现异常,新 promise 的状态变为 rejected,reason 就是错误对象
          rejectNext(e)
        }
      }
      const rejectNewPromise = reason => {
        try {
          // 正常情况
          if (typeof onRejected !== 'function') {
            // 不是函数,直接忽略,将 then 所属的 promise 作为 then 返回的 promise 的值 reject 来做到值的传递
            rejectNext(reason)
          } else {
            // 获取 then 函数回调的执行结果
            const res = onRejected(reason)
            if (res instanceof NewPromise) {
              // 当执行结果返回的是一个 promise 实例,等待这个 promise 状态改变后再改变 then 返回的 promise 的状态
              res.then(resolveNext, rejectNext)
            } else {
              // 当返回值是普通值,将其作为新 promise 的值 reject
              rejectNext(res)
            }
          }
        } catch (e) {
          // 出现异常,新 promise 的状态变为 rejected,reason 就是错误对象
          rejectNext(e)
        }
      }
      if (state === PENDING) {this.successCallback.push(resolveNewPromise)
        this.failureCallback.push(rejectNewPromise)
      }
      // 要保证在当前 promise 状态改变之后,再去改变新的 promise 的状态
      if (state === FULFILLED) {resolveNewPromise(value)
      }
      if (state === REJECTED) {rejectNewPromise(value)
      }
    })
  }
  catch(onRejected) {return this.then(undefined, onRejected)
  }
  finally(callback) {
    // 返回值是 promise 对象,回调在 then 中执行,也就符合了 promise 结束后调用的原则
    return this.then(
      // then 方法的 onFulfiled 和 onRejected 都会被传入,保证无论 resolved 或 rejected 都会被执行

      // 获取到 promise 执行成功的结果,将这个结果作为 finally 返回的新的 promise 的值
      res => NewPromise.resolve(callback())
          .then(() => {return res}),
      // 获取执行失败的结果。原理同上
      error => NewPromise.resolve(callback())
          .then(() => {throw error})
    )
  }
  static allSettled(instanceList) {return new NewPromise((resolve, reject) => {const results = []
      let count = 0
      if (instanceList.length === 0) {resolve([])
        return
      }
      // 定义一个函数,来生成结果数组
      const generateResult = (result, i) => {
        count++
        results[i] = result
        // 一旦全部执行完成,resolve 新返回的 promise
        if (count === instanceList.length) {resolve(results)
        }
      }
      instanceList.forEach((item, index) => {
        // 在每个 promise 完成后将状态记录到结果数组中
        this.resolve(item).then(
          value => {
            generateResult({
              status: FULFILLED,
              value
            }, index)
          },
          reason => {
            generateResult({
              status: REJECTED,
              reason
            }, index)
          }
        )
      })
    })
  }
  static resolve(value) {
    // value 不存在,直接返回一个 resolved 状态的 promise
    if (!value) {return new NewPromise(function (resolve) {resolve()
      })
    }
    // value 是 promise 实例,直接返回
    // 在这里需要首先判断是否是 promise 实例,再进行下边的判断
    // 因为我们自己构造的 promise 也是是 object,也有 then 方法
    if (value instanceof NewPromise) {return value}
    // 是 thenable 对象,返回的新的 promise 实例需要在 value 状态改变后再改变,且状态跟随 value 的状态
    if (typeof value === 'object' && typeof value.then === 'function') {return new NewPromise((resolve, reject) => {value.then(resolve, reject)
      })
    }
    // value 是普通值,返回新的 promise 并 resolve 这个普通值
    return new NewPromise(resolve => {resolve(value)
    })
  }
  static reject(reason) {return new NewPromise((resolve, reject) => {reject(reason)
    })
  }
  static all(instanceList) {return new NewPromise((resolve, reject) => {
      // 定义存放结果的数组
      const results = []
      let count = 0
      if (instanceList.length === 0) {resolve(results)
        return
      }
      instanceList.forEach((item, index) => {
        // 由于实例列表中的每个元素可能是各种各样的,所以要用 this.resolve 方法包装一层
        this.resolve(item).then(res => {results[index] = res
          count++
          // 当都执行完,resolve 新返回的 promise
          if (count === instanceList.length) {resolve(results)
          }
        }, error => {
          // 一旦有一个出错,就 reject 新返回的 promise
          reject(error)
        })
      })
    })
  }
  static race(instanceList) {return new NewPromise((resolve, reject) => {if (instanceList.length === 0) {resolve([])
        return
      }
      instanceList.forEach(item => {
        // 由于实例列表中的每个元素可能是各种各样的,所以要用 this.resolve 方法包装一层
        this.resolve(item).then(res => {
          // 一旦有一个 resolve 了,那么新返回的 promise 状态就被 resolve
          resolve(res)
        }, error => {reject(error)
        })
      })
    })
  }
}

片尾广告

想看我写的更多技术文章可以关注公众号:一口一个前端

正文完
 0