夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • ES6简介
  • 变量的解构赋值
  • 字符串的扩展
  • 字符串的新增方法
  • 正则的扩展
  • 数值的扩展
  • 函数的扩展
  • 数组的扩展
  • 对象的扩展
  • 对象的新增方法
  • Symbol
  • Set 和 Map 数据结构
  • Proxy
  • Reflect
  • Promise 对象
  • Iterator 和 for-of 循环
  • Generator 函数的语法
  • Generator 函数的异步应用
  • async 函数
  • Class 的基本语法
  • Class 的继承
  • Module 的语法
  • Module 的加载实现
  • 编程风格
  • 读懂ES6规格
  • 异步遍历器
  • ArrayBuffer
  • 最新提案
  • 装饰器
  • 函数式编程
  • Mixin
  • SIMD
  • ES6中的链判断符
  • Promise原理探究
    • 1. Promise 基本结构
    • 2. Promise 状态和值
    • 3. Promise 的 then 方法
    • 4.PromiseA+规范实现
  • 实用新规范
  • 《ES6教程》
夜猫子
2023-01-29
目录

Promise原理探究

# 深入探究 Promise 原理

这里只介绍 Promise 的基本思想和代码实现,不对其用法做说明。末尾附上 PromiseA+ 实现源码。

# 1. Promise 基本结构

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('FULFILLED')
  }, 1000)
})
1
2
3
4
5

构造函数Promise必须接受一个函数作为参数,我们称该函数为handle,handle又包含resolve和reject两个参数,它们是两个函数。

定义一个判断一个变量是否为函数的方法,后面会用到

// 判断变量否为function
const isFunction = variable => typeof variable === 'function'
1
2

首先,我们定义一个名为 MyPromise 的 Class,它接受一个函数 handle 作为参数

class MyPromise {
  constructor (handle) {
    if (!isFunction(handle)) {
      throw new Error('MyPromise must accept a function as a parameter')
    }
  }
}
1
2
3
4
5
6
7

再往下看

# 2. Promise 状态和值

Promise 对象存在以下三种状态:

  • Pending(进行中)
  • Fulfilled(已成功)
  • Rejected(已失败)

状态只能由 Pending 变为 Fulfilled 或由 Pending 变为 Rejected ,且状态改变之后不会在发生变化,会一直保持这个状态。

Promise的值是指状态改变时传递给回调函数的值

上文中handle函数包含 resolve 和 reject 两个参数,它们是两个函数,可以用于改变 Promise 的状态和传入 Promise 的值

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('FULFILLED')
  }, 1000)
})
1
2
3
4
5

这里 resolve 传入的 "FULFILLED" 就是 Promise 的值

resolve` 和 `reject
1
  • resolve : 将Promise对象的状态从 Pending(进行中) 变为 Fulfilled(已成功)
  • reject : 将Promise对象的状态从 Pending(进行中) 变为 Rejected(已失败)
  • resolve 和 reject 都可以传入任意类型的值作为实参,表示 Promise 对象成功(Fulfilled)和失败(Rejected)的值

了解了 Promise 的状态和值,接下来,我们为 MyPromise 添加状态属性和值

首先定义三个常量,用于标记Promise对象的三种状态

// 定义Promise的三种状态常量
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
1
2
3
4

再为 MyPromise 添加状态和值,并添加状态改变的执行逻辑

class MyPromise {
  constructor (handle) {
    if (!isFunction(handle)) {
      throw new Error('MyPromise must accept a function as a parameter')
    }
    // 添加状态
    this._status = PENDING
    // 添加状态
    this._value = undefined
    // 执行handle
    try {
      handle(this._resolve.bind(this), this._reject.bind(this)) 
    } catch (err) {
      this._reject(err)
    }
  }
  // 添加resovle时执行的函数
  _resolve (val) {
    if (this._status !== PENDING) return
    this._status = FULFILLED
    this._value = val
  }
  // 添加reject时执行的函数
  _reject (err) { 
    if (this._status !== PENDING) return
    this._status = REJECTED
    this._value = err
  }
}
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

这样就实现了 Promise 状态和值的改变。下面说一说 Promise 的核心: then 方法

# 3. Promise 的 then 方法

Promise 对象的 then 方法接受两个参数:

promise.then(onFulfilled, onRejected)
1

参数可选

onFulfilled 和 onRejected 都是可选参数。

  • 如果 onFulfilled 或 onRejected 不是函数,其必须被忽略

onFulfilled 特性

如果 onFulfilled 是函数:

  • 当 promise 状态变为成功时必须被调用,其第一个参数为 promise 成功状态传入的值( resolve 执行时传入的值)
  • 在 promise 状态改变前其不可被调用
  • 其调用次数不可超过一次

onRejected 特性

如果 onRejected 是函数:

  • 当 promise 状态变为失败时必须被调用,其第一个参数为 promise 失败状态传入的值( reject 执行时传入的值)
  • 在 promise 状态改变前其不可被调用
  • 其调用次数不可超过一次

多次调用

then 方法可以被同一个 promise 对象调用多次

  • 当 promise 成功状态时,所有 onFulfilled 需按照其注册顺序依次回调
  • 当 promise 失败状态时,所有 onRejected 需按照其注册顺序依次回调

返回

then 方法必须返回一个新的 promise 对象

promise2 = promise1.then(onFulfilled, onRejected);
1

因此 promise 支持链式调用

promise1.then(onFulfilled1, onRejected1).then(onFulfilled2, onRejected2);
1

这里涉及到 Promise 的执行规则,包括“值的传递”和“错误捕获”机制:

1、如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)

  • 若 x 不为 Promise ,则使 x 直接作为新返回的 Promise 对象的值, 即新的onFulfilled 或者 onRejected 函数的参数.
  • 若 x 为 Promise ,这时后一个回调函数,就会等待该 Promise 对象(即 x )的状态发生变化,才会被调用,并且新的 Promise 状态和 x 的状态相同。

下面的例子用于帮助理解:

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve()
  }, 1000)
})
promise2 = promise1.then(res => {
  // 返回一个普通值
  return '这里返回一个普通值'
})
promise2.then(res => {
  console.log(res) //1秒后打印出:这里返回一个普通值
})
 
let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve()
  }, 1000)
})
promise2 = promise1.then(res => {
  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    setTimeout(() => {
     resolve('这里返回一个Promise')
    }, 2000)
  })
})
promise2.then(res => {
  console.log(res) //3秒后打印出:这里返回一个Promise
})
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

2、如果 onFulfilled 或者onRejected 抛出一个异常 e ,则 promise2 必须变为失败(Rejected),并返回失败的值 e,例如:

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
promise2 = promise1.then(res => {
  throw new Error('这里抛出一个异常e')
})
promise2.then(res => {
  console.log(res)
}, err => {
  console.log(err) //1秒后打印出:这里抛出一个异常e
})
1
2
3
4
5
6
7
8
9
10
11
12
13

3、如果onFulfilled 不是函数且 promise1 状态为成功(Fulfilled), promise2 必须变为成功(Fulfilled)并返回 promise1 成功的值,例如:

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
promise2 = promise1.then('这里的onFulfilled本来是一个函数,但现在不是')
promise2.then(res => {
  console.log(res) // 1秒后打印出:success
}, err => {
  console.log(err)
})
 
1
2
3
4
5
6
7
8
9
10
11
12

4、如果 onRejected 不是函数且 promise1 状态为失败(Rejected),promise2必须变为失败(Rejected) 并返回 promise1 失败的值,例如:

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('fail')
  }, 1000)
})
promise2 = promise1.then(res => res, '这里的onRejected本来是一个函数,但现在不是')
promise2.then(res => {
  console.log(res)
}, err => {
  console.log(err)  // 1秒后打印出:fail
})
 
1
2
3
4
5
6
7
8
9
10
11
12

根据上面的规则,我们来为 完善 MyPromise

修改 constructor : 增加执行队列

由于 then 方法支持多次调用,我们可以维护两个数组,将每次 then 方法注册时的回调函数添加到数组中,等待执行

constructor (handle) {
  if (!isFunction(handle)) {
    throw new Error('MyPromise must accept a function as a parameter')
  }
  // 添加状态
  this._status = PENDING
  // 添加状态
  this._value = undefined
  // 添加成功回调函数队列
  this._fulfilledQueues = []
  // 添加失败回调函数队列
  this._rejectedQueues = []
  // 执行handle
  try {
    handle(this._resolve.bind(this), this._reject.bind(this)) 
  } catch (err) {
    this._reject(err)
  }
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

添加then方法

首先,then 返回一个新的 Promise 对象,并且需要将回调函数加入到执行队列中

// 添加then方法
then (onFulfilled, onRejected) {
  const { _value, _status } = this
  switch (_status) {
    // 当状态为pending时,将then方法回调函数加入执行队列等待执行
    case PENDING:
      this._fulfilledQueues.push(onFulfilled)
      this._rejectedQueues.push(onRejected)
      break
    // 当状态已经改变时,立即执行对应的回调函数
    case FULFILLED:
      onFulfilled(_value)
      break
    case REJECTED:
      onRejected(_value)
      break
  }
  // 返回一个新的Promise对象
  return new MyPromise((onFulfilledNext, onRejectedNext) => {
  })
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

那返回的新的 Promise 对象什么时候改变状态?改变为哪种状态呢?

根据上文中 then 方法的规则,我们知道返回的新的 Promise 对象的状态依赖于当前 then 方法回调函数执行的情况以及返回值,例如 then 的参数是否为一个函数、回调函数执行是否出错、返回值是否为 Promise 对象。

我们来进一步完善 then 方法:

// 添加then方法
then (onFulfilled, onRejected) {
  const { _value, _status } = this
  // 返回一个新的Promise对象
  return new MyPromise((onFulfilledNext, onRejectedNext) => {
    // 封装一个成功时执行的函数
    let fulfilled = value => {
      try {
        if (!isFunction(onFulfilled)) {
          onFulfilledNext(value)
        } else {
          let res =  onFulfilled(value);
          if (res instanceof MyPromise) {
            // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
            res.then(onFulfilledNext, onRejectedNext)
          } else {
            //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
            onFulfilledNext(res)
          }
        }
      } catch (err) {
        // 如果函数执行出错,新的Promise对象的状态为失败
        onRejectedNext(err)
      }
    }
    // 封装一个失败时执行的函数
    let rejected = error => {
      try {
        if (!isFunction(onRejected)) {
          onRejectedNext(error)
        } else {
            let res = onRejected(error);
            if (res instanceof MyPromise) {
              // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
              res.then(onFulfilledNext, onRejectedNext)
            } else {
              //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
              onFulfilledNext(res)
            }
        }
      } catch (err) {
        // 如果函数执行出错,新的Promise对象的状态为失败
        onRejectedNext(err)
      }
    }
    switch (_status) {
      // 当状态为pending时,将then方法回调函数加入执行队列等待执行
      case PENDING:
        this._fulfilledQueues.push(fulfilled)
        this._rejectedQueues.push(rejected)
        break
      // 当状态已经改变时,立即执行对应的回调函数
      case FULFILLED:
        fulfilled(_value)
        break
      case REJECTED:
        rejected(_value)
        break
    }
  })
}
 
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
58
59
60
61
62

这一部分可能不太好理解,读者需要结合上文中 then 方法的规则来细细的分析。

接着修改 _resolve 和 _reject :依次执行队列中的函数

当 resolve 或 reject 方法执行时,我们依次提取成功或失败任务队列当中的函数开始执行,并清空队列,从而实现 then 方法的多次调用,实现的代码如下:

// 添加resovle时执行的函数
_resolve (val) {
  if (this._status !== PENDING) return
  // 依次执行成功队列中的函数,并清空队列
  const run = () => {
    this._status = FULFILLED
    this._value = val
    let cb;
    while (cb = this._fulfilledQueues.shift()) {
      cb(val)
    }
  }
  // 为了支持同步的Promise,这里采用异步调用
  setTimeout(() => run(), 0)
}
// 添加reject时执行的函数
_reject (err) { 
  if (this._status !== PENDING) return
  // 依次执行失败队列中的函数,并清空队列
  const run = () => {
    this._status = REJECTED
    this._value = err
    let cb;
    while (cb = this._rejectedQueues.shift()) {
      cb(err)
    }
  }
  // 为了支持同步的Promise,这里采用异步调用
  setTimeout(run, 0)
}
 
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

这里还有一种特殊的情况,就是当 resolve 方法传入的参数为一个 Promise 对象时,则该 Promise 对象状态决定当前 Promise 对象的状态。

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})
 
1
2
3
4
5
6
7
8
9

上面代码中,p1 和 p2 都是 Promise 的实例,但是 p2 的resolve方法将 p1 作为参数,即一个异步操作的结果是返回另一个异步操作。

注意,这时 p1 的状态就会传递给 p2,也就是说,p1 的状态决定了 p2 的状态。如果 p1 的状态是Pending,那么 p2 的回调函数就会等待 p1 的状态改变;如果 p1 的状态已经是 Fulfilled 或者 Rejected,那么 p2 的回调函数将会立刻执行。

我们来修改_resolve来支持这样的特性

  // 添加resovle时执行的函数
  _resolve (val) {
    const run = () => {
      if (this._status !== PENDING) return
      // 依次执行成功队列中的函数,并清空队列
      const runFulfilled = (value) => {
        let cb;
        while (cb = this._fulfilledQueues.shift()) {
          cb(value)
        }
      }
      // 依次执行失败队列中的函数,并清空队列
      const runRejected = (error) => {
        let cb;
        while (cb = this._rejectedQueues.shift()) {
          cb(error)
        }
      }
      /* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
        当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
      */
      if (val instanceof MyPromise) {
        val.then(value => {
          this._value = value
          this._status = FULFILLED
          runFulfilled(value)
        }, err => {
          this._value = err
          this._status = REJECTED
          runRejected(err)
        })
      } else {
        this._value = val
        this._status = FULFILLED
        runFulfilled(val)
      }
    }
    // 为了支持同步的Promise,这里采用异步调用
    setTimeout(run, 0)
  }
 
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

这样一个Promise就基本实现了,现在我们来加一些其它的方法

catch 方法

相当于调用 then 方法, 但只传入 Rejected 状态的回调函数

// 添加catch方法
catch (onRejected) {
  return this.then(undefined, onRejected)
}
 
1
2
3
4
5

静态 resolve 方法

// 添加静态resolve方法
static resolve (value) {
  // 如果参数是MyPromise实例,直接返回这个实例
  if (value instanceof MyPromise) return value
  return new MyPromise(resolve => resolve(value))
}
 
1
2
3
4
5
6
7

静态 reject 方法

// 添加静态reject方法
static reject (value) {
  return new MyPromise((resolve ,reject) => reject(value))
}
 
1
2
3
4
5

静态 all 方法

// 添加静态all方法
static all (list) {
  return new MyPromise((resolve, reject) => {
    /**
     * 返回值的集合
     */
    let values = []
    let count = 0
    for (let [i, p] of list.entries()) {
      // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
      this.resolve(p).then(res => {
        values[i] = res
        count++
        // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
        if (count === list.length) resolve(values)
      }, err => {
        // 有一个被rejected时返回的MyPromise状态就变成rejected
        reject(err)
      })
    }
  })
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

静态 race 方法

// 添加静态race方法
static race (list) {
  return new MyPromise((resolve, reject) => {
    for (let p of list) {
      // 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
      this.resolve(p).then(res => {
        resolve(res)
      }, err => {
        reject(err)
      })
    }
  })
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14

finally 方法

finally 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作

finally (cb) {
  return this.then(
    value  => MyPromise.resolve(cb()).then(() => value),
    reason => MyPromise.resolve(cb()).then(() => { throw reason })
  );
};
 
1
2
3
4
5
6
7

这样一个完整的 Promsie 就实现了,大家对 Promise 的原理也有了解,可以让我们在使用Promise的时候更加清晰明了。

完整代码如下

  // 判断变量否为function
  const isFunction = variable => typeof variable === 'function'
  // 定义Promise的三种状态常量
  const PENDING = 'PENDING'
  const FULFILLED = 'FULFILLED'
  const REJECTED = 'REJECTED'

  class MyPromise {
    constructor (handle) {
      if (!isFunction(handle)) {
        throw new Error('MyPromise must accept a function as a parameter')
      }
      // 添加状态
      this._status = PENDING
      // 添加状态
      this._value = undefined
      // 添加成功回调函数队列
      this._fulfilledQueues = []
      // 添加失败回调函数队列
      this._rejectedQueues = []
      // 执行handle
      try {
        handle(this._resolve.bind(this), this._reject.bind(this)) 
      } catch (err) {
        this._reject(err)
      }
    }
    // 添加resovle时执行的函数
    _resolve (val) {
      const run = () => {
        if (this._status !== PENDING) return
        // 依次执行成功队列中的函数,并清空队列
        const runFulfilled = (value) => {
          let cb;
          while (cb = this._fulfilledQueues.shift()) {
            cb(value)
          }
        }
        // 依次执行失败队列中的函数,并清空队列
        const runRejected = (error) => {
          let cb;
          while (cb = this._rejectedQueues.shift()) {
            cb(error)
          }
        }
        /* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
          当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
        */
        if (val instanceof MyPromise) {
          val.then(value => {
            this._value = value
            this._status = FULFILLED
            runFulfilled(value)
          }, err => {
            this._value = err
            this._status = REJECTED
            runRejected(err)
          })
        } else {
          this._value = val
          this._status = FULFILLED
          runFulfilled(val)
        }
      }
      // 为了支持同步的Promise,这里采用异步调用
      setTimeout(run, 0)
    }
    // 添加reject时执行的函数
    _reject (err) { 
      if (this._status !== PENDING) return
      // 依次执行失败队列中的函数,并清空队列
      const run = () => {
        this._status = REJECTED
        this._value = err
        let cb;
        while (cb = this._rejectedQueues.shift()) {
          cb(err)
        }
      }
      // 为了支持同步的Promise,这里采用异步调用
      setTimeout(run, 0)
    }
    // 添加then方法
    then (onFulfilled, onRejected) {
      const { _value, _status } = this
      // 返回一个新的Promise对象
      return new MyPromise((onFulfilledNext, onRejectedNext) => {
        // 封装一个成功时执行的函数
        let fulfilled = value => {
          try {
            if (!isFunction(onFulfilled)) {
              onFulfilledNext(value)
            } else {
              let res =  onFulfilled(value);
              if (res instanceof MyPromise) {
                // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
                res.then(onFulfilledNext, onRejectedNext)
              } else {
                //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
                onFulfilledNext(res)
              }
            }
          } catch (err) {
            // 如果函数执行出错,新的Promise对象的状态为失败
            onRejectedNext(err)
          }
        }
        // 封装一个失败时执行的函数
        let rejected = error => {
          try {
            if (!isFunction(onRejected)) {
              onRejectedNext(error)
            } else {
                let res = onRejected(error);
                if (res instanceof MyPromise) {
                  // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
                  res.then(onFulfilledNext, onRejectedNext)
                } else {
                  //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
                  onFulfilledNext(res)
                }
            }
          } catch (err) {
            // 如果函数执行出错,新的Promise对象的状态为失败
            onRejectedNext(err)
          }
        }
        switch (_status) {
          // 当状态为pending时,将then方法回调函数加入执行队列等待执行
          case PENDING:
            this._fulfilledQueues.push(fulfilled)
            this._rejectedQueues.push(rejected)
            break
          // 当状态已经改变时,立即执行对应的回调函数
          case FULFILLED:
            fulfilled(_value)
            break
          case REJECTED:
            rejected(_value)
            break
        }
      })
    }
    // 添加catch方法
    catch (onRejected) {
      return this.then(undefined, onRejected)
    }
    // 添加静态resolve方法
    static resolve (value) {
      // 如果参数是MyPromise实例,直接返回这个实例
      if (value instanceof MyPromise) return value
      return new MyPromise(resolve => resolve(value))
    }
    // 添加静态reject方法
    static reject (value) {
      return new MyPromise((resolve ,reject) => reject(value))
    }
    // 添加静态all方法
    static all (list) {
      return new MyPromise((resolve, reject) => {
        /**
         * 返回值的集合
         */
        let values = []
        let count = 0
        for (let [i, p] of list.entries()) {
          // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
          this.resolve(p).then(res => {
            values[i] = res
            count++
            // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
            if (count === list.length) resolve(values)
          }, err => {
            // 有一个被rejected时返回的MyPromise状态就变成rejected
            reject(err)
          })
        }
      })
    }
    // 添加静态race方法
    static race (list) {
      return new MyPromise((resolve, reject) => {
        for (let p of list) {
          // 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
          this.resolve(p).then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        }
      })
    }
    finally (cb) {
      return this.then(
        value  => MyPromise.resolve(cb()).then(() => value),
        reason => MyPromise.resolve(cb()).then(() => { throw reason })
      );
    }
  }
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

# 4.PromiseA+规范实现

直接附上源码

const isFunction = function(fun) {
    return typeof fun === 'function';
};
const isObject = function(value) {
    return value !== null && typeof value === 'object';
};

// [[Resolve]](promise, x): 是promise的解决过程,判断x的值的类型以及它和promise实例的关系
// 需要进行 [[Resolve]](promise, x)的地方有:
// 1. then中的onFulfilled和onRejected的返回值res:[[Resolve]](promise, res)
// 2. _promiseResolve中,x为Promise的情况,对改promise的值y进行[[Resolve]](promise, y)
// 3. _promiseResolve中,x有then且then为函数的情况,该then的第一个参数是函数resolvePromise接收一个y为参数,对y进行[[Resolve]](promise, y)
class MyPromise {
    constructor(handle) {
        if (!isFunction(handle)) {
            throw new TypeError('MyPromise resolver is not a function');
        }
        // 当前promise的状态
        this._status = 'PENDING';
        // 当前promise的值
        this._value = undefined;
        // promise状态为'FULFILLED'时需要执行的注册事件队列
        this._fulfilledQueue = [];
        // promise状态为'REJECTED'时需要执行的注册事件队列
        this._rejectedQueue = [];
        // promise创建后,同步执行handle
        // 如果handle执行出错,则将promise的状态改为'REJECTED'
        try {
            handle(this._resolve.bind(this), this._reject.bind(this));
        } catch(err) {
            this._reject(err);
        }
    }
    _resolve(value) {
        if (this._status !== 'PENDING') {
            return;
        }
        const resolveHandle = (val) => {
            this._status = 'FULFILLED';
            this._value = val;
            while(this._fulfilledQueue.length) {
                const cb = this._fulfilledQueue.shift();
                cb(val);
            }
        }
        const rejectHandle = (reason) => {
            this._status = 'REJECTED';
            this._value = reason;
            while(this._rejectedQueue.length) {
                const cb = this._rejectedQueue.shift();
                cb(reason);
            }
        }
        // 判断resolve传入的是不是一个promise
        // 如果是,需要等待该promise的状态改变,新promise的状态和该状态相同
        // 注意:Promise/A+规范并没有这个规定
        if (value instanceof MyPromise) {
            if (value === this) {
                return rejectHandle(new TypeError(''));
            }
            value.then(resolveHandle, rejectHandle);
        } else {
            // 执行_fulfilledQueue中的任务
            // 所有 onFulfilled 需按照其注册顺序依次回调
            resolveHandle(value);
        }
    }
    _reject(reason) {
        if (this._status !== 'PENDING') {
            return;
        }
        this._status = 'REJECTED';
        this._value = reason;
        // 执行_rejectedQueue中的任务
        // 所有的 onRejected 需按照其注册顺序依次回调
        while(this._rejectedQueue.length) {
            const cb = this._rejectedQueue.shift();
            cb(reason);
        }
    }
    // Promise解决过程
    // [[Resolve]](promise, x)
    _promiseResolve(promise, x, resolve, reject) {
        // x与promise相等
        // 如果promise和x指向同一对象,以TypeError为reason执行reject
        if (x === promise) {
            return reject(new TypeError(''));
        }
        // x为Promise
        // 如果 x 为 Promise ,则使 promise 接受 x 的状态
        if (x instanceof MyPromise) {
            // x的value为y, 运行[[Resolve]](promise, y):this._promiseResolve(promise, y, resolve, reject);
            // 有可能是一个promise,所以需要调用解决过程
            x.then(
                y => {
                    this._promiseResolve(promise, y, resolve, reject);
                },
                reject
            );
            return;
        }
        // x为对象或函数
        if (isFunction(x) || isObject(x)) {
            let isCalled  = false;
            let then;
            // 如果取 x.then 的值时抛出错误 e ,则以e为reason执行reject(e)
            try {
                then = x.then;
            } catch(e) {
                return reject(e);
            }
          
            // 如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise:
            // 如果 resolvePromise 以 y 为参数被调用,则运行 [[Resolve]](promise, y): this._promiseResolve(promise, y, resolve, reject);
            // 如果 rejectPromise 以 r 为参数被调用,则执行reject(r);
            // 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
            if (isFunction(then)) {
                const resolvePromise = y => {
                    if (isCalled) {
                        return;
                    }
                    isCalled = true;
                    this._promiseResolve(promise, y, resolve, reject);
                }
                const rejectPromise = (r) => {
                    if (isCalled) {
                        return;
                    }
                    isCalled = true;
                    reject(r);
                }
                // 如果调用 then 方法抛出了异常 e
                // 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
                // 否则以 e 为reason执行reject(e);
                try {
                    then.call(x, resolvePromise, rejectPromise);
                } catch(e) {
                    if (isCalled) {
                        return;
                    }
                    reject(e);
                }
            // 如果 then 不是函数(包括没有then的情况),以 x 为参数执行resolve(x);
            } else {
                resolve(x);
            }
            return;
        }
        // 如果 x 不为对象或者函数,以 x 为参数执行resolve(x);
        resolve(x);
    }
    then(onFulfilled, onRejected) {
        const promise = new MyPromise((resolveNext, rejectedNext) => {
            const fulfilledHandle = (value) => {
                queueMicrotask(() => {
                    if (!isFunction(onFulfilled)) {
                        resolveNext(value);
                    } else {
                        try {
                            const res = onFulfilled(value);
                            // 执行promise的解决过程
                            this._promiseResolve(promise, res, resolveNext, rejectedNext);
                        } catch(err) {
                            rejectedNext(err);
                        }
                    }
                });
                
            };
            const rejectedHandle = (reason) => {
                queueMicrotask(() => {
                    if (!isFunction(onRejected)) {
                        rejectedNext(reason);
                    } else {
                        try {
                            const res = onRejected(reason);
                            // 执行promise的解决过程
                            this._promiseResolve(promise, res, resolveNext, rejectedNext);
                        } catch(err) {
                            rejectedNext(err);
                        }
                    }
                });
            };

            switch(this._status) {
                // 状态为"PENDING'时,将任务加入到队列中等待promise的状态改变时执行
                case 'PENDING':
                    this._fulfilledQueue.push(fulfilledHandle);
                    this._rejectedQueue.push(rejectedHandle);
                    break;
                case 'FULFILLED':
                    fulfilledHandle(this._value);
                    break;
                case 'REJECTED':
                    rejectedHandle(this._value);
                    break;
                default:
            }
        });
        return promise;
    }
    catch(onRejected) {
        return this.then(undefined, onRejected);
    }
    // finally返回的新promise的状态取决于调用finally的promise的状态
    // finally方法总是会返回原来的值
    // 如果cb返回的是一个promise, 会等待该promise的状态改变
    finally(cb) {
        return this.then(
            (value) => MyPromise.resolve(cb()).then(() => value),
            (err) => MyPromise.resolve(cb()).then(() => { throw err })
        );
    }
    static resolve(p) {
        if (p instanceof MyPromise) {
            return p;
        }
        return new MyPromise((resolve) => {
            resolve(p);
        });
    }
    // MyPromise.reject()方法的参数,会原封不动地作为reject的理由, 不会处理传入promise的情况
    static reject(p) {
        return new MyPromise((resolve, reject) => {
            reject(p);
        });
    }
    // 如果不是传入的数组某一项不是MyPromise实例,就会先调用MyPromise.resolve()方法,将参数转为MyPromise实例,再进一步处理
    static all(promiseList) {
        return new MyPromise((resolve, reject) => {
            let list;
            // 如果promiseList不是iterator,会报错,直接reject
            try {
                list = [...promiseList];   
            } catch(err) {
                reject(new TypeError(`${promiseList} is not iterable (cannot read property Symbol(Symbol.iterator))`));
                return;
            }

            const len = list.length;
            // promiseList为空数组,resolve
            if (len === 0) {
                 resolve([]);
            }
            
            let fulfilledCount = 0;
            const res = [];
            for (const [i, p] of list.entries()) {
                MyPromise.resolve(p)
                    .then((value) => {
                        res[i] = value;
                        fulfilledCount++;
                        if (fulfilledCount === len) {
                            resolve(res);
                        }
                    }, (err) => {
                        reject(err);
                    });
            }
        });
    }
    // 如果不是传入的数组某一项不是MyPromise实例,就会先调用MyPromise.resolve()方法,将参数转为MyPromise实例,再进一步处理
    static race(promiseList) {
        return new MyPromise((resolve, reject) => {
            let list;
            // 如果promiseList不是iterator,会报错,直接reject
            try {
                list = [...promiseList];   
            } catch(err) {
                reject(new TypeError(`${promiseList} is not iterable (cannot read property Symbol(Symbol.iterator))`));
                return;
            }
            // 会等待第一个改变状态的promise,如果promiseList为空数组,则会一直是pending状态
            for (const p of list) {
                MyPromise.resolve(p)
                    .then((value) => {
                        resolve(value);
                    }, (err) => {
                        reject(err);
                    });
            }
        });
    }
    // MyPromise.allSettled()方法接受一组Promise实例作为参数,f返回一个新的Promise实例,且新实例的状态只可能变成fulfilled
    // 只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。该方法由 ES2020 引入。
    /** 返回新的promise的结果
     * [
        { status: 'fulfilled', value: 42 },
        { status: 'rejected', reason: -1 }
        ]
     */
    static allSettled(promiseList) {
        return new MyPromise((resolve, reject) => {
            let list;
            // 如果promiseList不是iterator,会报错,直接reject
            try {
                list = [...promiseList];   
            } catch(err) {
                reject(new TypeError(`${promiseList} is not iterable (cannot read property Symbol(Symbol.iterator))`));
                return;
            }

            let unsettledCount = list.length;
            // promiseList为空数组,resolve
            if (unsettledCount === 0) {
                 resolve([]);
            }
            
            const res = [];
            for (const [i, p] of list.entries()) {
                MyPromise.resolve(p)
                    .then(value => {
                        res[i] = {status: 'fulfilled', value};
                    }, reason => {
                        res[i] = {status: 'rejected', reason};
                    }).finally(() => {
                        unsettledCount--;
                        if (unsettledCount === 0) {
                            resolve(res);
                        }
                    });
            }
        });
    }
    // 与Promise.all相反,如果有一个为fulfilled,返回的新promise就是fulfilled,否则就是rejected
    // 数组为空或者所有promise都是rejected状态,返回一个AggregateError:new AggregateError(errors, 'All promises were rejected')
    // errors数组保存每个失败的原因,如果数组为空,则errors为空
    static any(promiseList) {
        return new MyPromise((resolve, reject) => {
            let list;
            // 如果promiseList不是iterator,会报错,直接reject
            try {
                list = [...promiseList];   
            } catch(err) {
                reject(new TypeError(`${promiseList} is not iterable (cannot read property Symbol(Symbol.iterator))`));
                return;
            }

            const len = list.length;
            const errors = [];
            // promiseList为空数组,表示没有一个promise会是fulfilled状态,所以结果为rejected
            if (len === 0) {
                reject(new AggregateError(errors, 'All promises were rejected'));
            }
            let rejectedCount = 0;

            for (const [i, p] of list.entries()) {
                MyPromise.resolve(p)
                    .then(
                        value => {
                            resolve(value);
                        },
                        err => {
                            errors[i] = err;
                            rejectedCount++;
                            if (rejectedCount === len) {
                               reject(new AggregateError(errors, 'All promises were rejected'));
                            }
                        }
                    );
            }
        });
    }
}

// 测试代码
// MyPromise.deferred = function() {
//     var result = {};
//     result.promise = new MyPromise(function(resolve, reject){
//       result.resolve = resolve;
//       result.reject = reject;
//     });
  
//     return result;
// }


// var promisesAplusTests = require("promises-aplus-tests");
// const { reject } = require("underscore");

// promisesAplusTests(MyPromise, function (err) {
//     console.log(err);
//     // All done; output is in the console. Or check `err` for number of failures.
// });
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
编辑 (opens new window)
上次更新: 2023/7/11 18:57:41
ES6中的链判断符
实用新规范

← ES6中的链判断符 实用新规范→

最近更新
01
IoC 解决了什么痛点问题?
03-10
02
如何调试 Nest 项目
03-10
03
Provider注入对象
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式