Promise实现
Promise方法是可以非常基础但是又非常重要的API,今天就一步一步刨析Promise 来完成
# 什么是Promise
- Promise是异步回调的一种解决方案。在传统的异步实现方案中都是通过回调来解决的。
 - 但是过多的回调难以维护,也会形式一种所称“地狱嵌套” 的状态。
 - Promise 可以使用then链来解决这个问题。但是又不是尽善尽美的。过多的then链也会给使用者带来困扰
 - 解决下来我们一起探究下Promise到底如何实现吧
 
# 基础辅助函数
# 1.
const PromiseStatus = {
  Pending: 'Pending',
  Fulfilled: 'Fulfilled',
  Rejected: 'Rejected'
}
 1
2
3
4
5
2
3
4
5
- 上述代码分别表示Promise的三种状态
 - Promise中状态不可逆的,只能是从等待 => 成功/ 等待 => 失败。 一旦状态修改后不可再变化
 
# 2.
const isObject = (value) =>
  Object.prototype.toString.call(value) === '[object Object]'
const isPromise = (obj) =>
  (isObject(obj) || typeof obj === 'function') && typeof obj.then === 'function'
 1
2
3
4
2
3
4
- 上述代码为了判断是否是对象 或是 是否是Promise
 
# 3.
/**
 * @author lihh
 * @description 深度解析promise 返回值
 * @param p 表示上次的promise 实例
 * @param preValue 上一次的值
 * @param resolve then 返回promise中的 resolve
 * @param reject then返回promise中的 reject
 */
const depthResolvePromise = (p, preValue, resolve, reject) => {
    // 如果是返回value 跟实例是同一个的话 直接报错
    if (p === preValue) {
      throw new TypeError('the same instance cannot be referenced cyclically ')
    }
    // 判断是否是对象 如果不是对象的话 直接执行resolve
    if (isObject(preValue) || typeof preValue === 'function') {
      const then = preValue.then
      // 如果then属性不是函数的话,直接执行resolve
      if (typeof then === 'function') {
        // 从这几话中可以得到 .then 作为一个新的Promise的状态,成功与否取决于内部返回Promise的状态
        try {
          then.call(
            preValue,
            (y) => {
              depthResolvePromise(p, y, resolve, reject)
            },
            (r) => {
              depthResolvePromise(p, r, resolve, reject)
            }
          )
        } catch (e) {
          reject(e)
        }
      } else {
        resolve(preValue)
      }
    } else {
      resolve(preValue)
    }
  }
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
- 上述的代码主要是为了进一步解析promise,有可能Promise实例返回内容还是一个Promise实例
 - 上述代码中如果是被异常捕获到,直接执行reject函数
 - 如果
preValue不是promise 实例的话,统一直接resolve函数。都是成功的状态(无论返回值是null/ undefined等都作为成功的状态) - 一直递归调用函数
depthResolvePromise直到解析成为一个非promise实例的普通值为止 
# Promise构造函数
function Promise(execution) {
  // 成功状态的值
  this.value = ''
  // 失败的值
  this.reason = ''
  // 表示每个promise 实例的状态
  this.state = PromiseStatus.Pending
  // 为了应对异步情况。 保存onFulfilled/ onRejected 方法
  this.fulfilledCallback = []
  this.rejectedCallback = []
  // 构造函数的resolve 方法
  const resolveFn = (value) => {
    if (value instanceof Promise) {
      return value.then(resolveFn, rejectFn)
    }
    if (this.state !== PromiseStatus.Pending) return
    this.value = value
    this.state = PromiseStatus.Fulfilled
    this.fulfilledCallback.forEach((fn) => fn(this.value))
  }
  // 构造函数的reject方法
  const rejectFn = (reason) => {
    if (this.state !== PromiseStatus.Pending) return
    this.reason = reason
    this.state = PromiseStatus.Rejected
    this.rejectedCallback.forEach((fn) => fn(this.reason))
  }
  try {
    execution(resolveFn, rejectFn)
  } catch (e) {
    rejectFn(e)
  }
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
上述代码是Promise 构造函数执行的代码
首先一点,Promise构造函数是一个同步执行的过程,是then方法是异步的。所以不要弄混了
如果执行构造函数期间发生异常了,捕获到后,直接执行reject方法
可能用户使用Promise。调用resolve方法的时候,传递的还是一个promise实例。这个时候需要特殊的判断,如下记:
if (value instanceof Promise) { return value.then(resolveFn, rejectFn) }1
2
3属性
fulfilledCallback以及rejectedCallback为了应对异步情况。因为执行then的时候,promise实例状态还没有修改,所以需要优先保存
# Promise.prototype.then
/**
 * @author lihh
 * @description Promise then方法 本身是一个微任务
 * @param onFulfilled 成功状态的回调
 * @param onRejected 失败状态的回调
 */
Promise.prototype.then = function (onFulfilled, onRejected) {
  if (typeof onFulfilled !== 'function') onFulfilled = (x) => x
  if (typeof onRejected !== 'function')
    onRejected = (err) => {
      throw err
    }
  // 状态resolve/ rejected 的场合
  if ([PromiseStatus.Fulfilled, PromiseStatus.Rejected].includes(this.state)) {
    // 此处代表返回的一个新的实例
    const p = new Promise((resolve, reject) => {
      queueMicrotask(() => {
        try {
          const r =
            this.state === PromiseStatus.Fulfilled
              ? onFulfilled(this.value)
              : onRejected(this.reason)
          depthResolvePromise(p, r, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
    })
    return p
  }
  // 状态是pending 的场合
  const p = new Promise((resolve, reject) => {
    this.fulfilledCallback.push((value) => {
      queueMicrotask(() => {
        try {
          const r = onFulfilled(value)
          depthResolvePromise(p, r, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
    })
    this.rejectedCallback.push((reason) => {
      queueMicrotask(() => {
        try {
          const r = onRejected(reason)
          depthResolvePromise(p, r, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
    })
  })
  return p
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
- 首先then函数的成功回调以及失败的回调,可以不进行传值
 - 针对状态是:
fulfilled,rejected,pending进行不同的处理 - 但是then方法一定会返回一个全新的promise。因为promise状态不可逆的
 
# Promise.prototype.finally
Promise.prototype.finally = function (fn) {
  try {
    fn()
    return this.then(null, null)
  } catch (e) {
    const callback = () => {
      throw e
    }
    return this.then(callback, callback)
  }
}
 1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- finally 实现原理就是不同的场合 调用then方法
 - 如果finally函数调用过程中有异常抛出,后续的会进行异常处理。其余的场合无论finally会返回什么样的结构,都不会改变其promise状态
 
# Promise.prototype.catch
Promise.prototype.catch = function (fn) {
  // catch 执行的逻辑就是then 只执行error的分支
  return this.then(null, fn)
}
 1
2
3
4
2
3
4
catch方法其实就是
then函数的另一种实现
# Promise.abort
自己添加的方法,在原生的Promise中并没有,可以中断promise的执行
/**
 * @author lihh
 * @description promise中断方法
 * @param userPromise 用户自己promise
 */
Promise.abort = function (userPromise) {
  let abort
  const innerPromise = new Promise((_, reject) => {
    abort = reject
  })
  const racePromise = Promise.race([userPromise, innerPromise])
  racePromise.abort = abort
  return racePromise
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
其实就是利用了函数
race的原理,返回第一个成功/ 失败的状态
# Promise.resolve
/**
 * @author lihh
 * @description 直接返回一个具有成功状态的promise
 * @param params 传递参数
 * @returns {Promise}
 */
Promise.resolve = function (params) {
  return new Promise((resolve) => {
    resolve(params)
  })
}
 1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
默认就是一个成功的状态promise
# Promise.reject
/**
 * @author lihh
 * @description 直接返回一个具有失败状态的 promise
 * @param params 传递参数
 * @returns {Promise}
 */
Promise.reject = function (params) {
  return new Promise((_, reject) => {
    reject(params)
  })
}
 1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
默认就是一个失败的promise
# Promise.race
/***
 * @author lihh
 * @description 返回一个promise的状态,无论是成功还是失败
 * @param allPromise 表示所有的promise
 */
Promise.race = function (allPromise = []) {
  return new Promise((resolve, reject) => {
    let i = 0
    for (; i < allPromise.length; i += 1) {
      const item = allPromise[i]
      if (!isPromise(item)) {
        return resolve(item)
      } else {
        item.then(resolve, reject)
        return
      }
    }
  })
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 返回第一个成功或是失败的结果
 - mdn解释
 
# Promise.any
/**
 * @author lihh
 * @description 一旦出现一个可兑现状态,就是可兑现的状态,如果全都不可兑现,就是rejected状态
 * @param allPromise 表示所有的promise
 */
Promise.any = function (allPromise) {
  return new Promise((resolve, reject) => {
    let count = 0
    const rejectedCallback = () => {
      count += 1
      if (count >= allPromise.length) {
        reject('[AggregateError: All promises were rejected]')
      }
    }
    let i = 0
    for (; i < allPromise.length; i += 1) {
      const item = allPromise[i]
      if (!isPromise(item)) {
        return resolve(item)
      } else {
        item.then(
          (res) => {
            return resolve(res)
          },
          () => {
            rejectedCallback()
          }
        )
      }
    }
  })
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
- 如果一旦有任意一个promise的状态是成功状态,该结果就会被返回
 - 如果所有的promise状态都失败了,则返回失败的状态
 - mdn解释
 
# Promise.allSettled
/**
 * @author lihh
 * @description 批量执行promise数组 无论是成功还是失败都会返回 最后返回一个promise  返回结构是:{status: 'fulfilled/ rejected', value}
 * @param allPromise 传递参数
 */
Promise.allSettled = function (allPromise = []) {
  return new Promise((resolve) => {
    let count = 0
    const resultArr = []
    const callback = (index, value, status) => {
      resultArr[index] = {status, value}
      count += 1
      if (count >= allPromise.length) {
        resolve(resultArr)
      }
    }
    allPromise.forEach((item, index) => {
      if (!isPromise(item)) {
        callback(index, item, 'fulfilled')
      } else {
        item.then(
          (res) => {
            callback(index, res, 'fulfilled')
          },
          (err) => {
            callback(index, err, 'rejected')
          }
        )
      }
    })
  })
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- 执行所有的promise 无论是成功状态还是失败的状态 都会以指定的格式返回
 - mdn解释
 
# Promise.all
/**
 * @author lihh
 * @description 多个promise 同时发出请求,如果全部成功结果 以数组的形式全部返回
 * @param promiseAll promise 数组
 * @returns {Promise} 返回的promise
 */
Promise.all = function (promiseAll = []) {
  return new Promise((resolve, reject) => {
    const resultArr = []
    let count = 0
    const callback = (index, res) => {
      count += 1
      resultArr[index] = res
      if (count >= promiseAll.length) {
        resolve(resultArr)
      }
    }
    for (let i = 0; i < promiseAll.length; i += 1) {
      const p = promiseAll[i]
      if (!isPromise(p)) {
        callback(i, p)
      } else {
        p.then((res) => {
          callback(i, res)
        }, reject)
      }
    }
  })
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 如果所有的promise 都是成功状态,会以数组的形式进行返回
 - 一旦有一个状态是rejected状态。立马执行失败的操作
 - mdn解释