技术分享
首页
  • JavaScript

    • 构造函数和原型
    • Cookie和Session
    • Object.create(null)和{}
    • TypeScript配置
    • typescript入门到进阶
  • 框架

    • Vue-Router
    • React基础入门
  • 其它

    • Http协议
    • 跨域问题总结
  • 分析Promise实现
  • Axios源码分析
  • Webpack原理
  • vueRouter源码分析
  • Vue

    • Vite快速搭建Vue3+TypeScript项目
    • Cordova打包Vue项目的问题
    • Vue将汉字转为拼音,取出首字母
  • JavaScript

    • new Function
  • 后端

    • Node.js中使用Crypto生成Token
    • Body-Parser处理多层对象的问题
  • 其它

    • 项目Demo汇总
    • Vuepress+Vercel搭建个人站点
    • 项目中能用到的
    • husky规范代码提交
  • Mongoose基础
  • Multer文件上传中间件的使用
  • JavaScript

    • 浅谈两数全等
    • JavaScript进制转换
    • 手写bind,apply,call和new
  • 算法

    • 数组去重和排序
    • 数组扁平化
    • 斐波那契数列
  • JavaScript 数据结构
  • 其它

    • webpack面试题
    • vite面试题
    • svg和canvas的优缺点
    • TypeScript面试题
    • Vue常见面试题
  • 计算机网络

    • 数据链路层
    • 网络层
  • Git的使用
  • Nginx的使用
  • CentOS7安装Nginx
  • 正则表达式
  • SEO搜索引擎优化
  • Serverless介绍
友链
GitHub (opens new window)

鑫生活

总有人要赢,为什么不能是我
首页
  • JavaScript

    • 构造函数和原型
    • Cookie和Session
    • Object.create(null)和{}
    • TypeScript配置
    • typescript入门到进阶
  • 框架

    • Vue-Router
    • React基础入门
  • 其它

    • Http协议
    • 跨域问题总结
  • 分析Promise实现
  • Axios源码分析
  • Webpack原理
  • vueRouter源码分析
  • Vue

    • Vite快速搭建Vue3+TypeScript项目
    • Cordova打包Vue项目的问题
    • Vue将汉字转为拼音,取出首字母
  • JavaScript

    • new Function
  • 后端

    • Node.js中使用Crypto生成Token
    • Body-Parser处理多层对象的问题
  • 其它

    • 项目Demo汇总
    • Vuepress+Vercel搭建个人站点
    • 项目中能用到的
    • husky规范代码提交
  • Mongoose基础
  • Multer文件上传中间件的使用
  • JavaScript

    • 浅谈两数全等
    • JavaScript进制转换
    • 手写bind,apply,call和new
  • 算法

    • 数组去重和排序
    • 数组扁平化
    • 斐波那契数列
  • JavaScript 数据结构
  • 其它

    • webpack面试题
    • vite面试题
    • svg和canvas的优缺点
    • TypeScript面试题
    • Vue常见面试题
  • 计算机网络

    • 数据链路层
    • 网络层
  • Git的使用
  • Nginx的使用
  • CentOS7安装Nginx
  • 正则表达式
  • SEO搜索引擎优化
  • Serverless介绍
友链
GitHub (opens new window)
  • 分析Promise实现
    • 初识 Promise
    • 手动实现 Promise
      • Promise.then 方法实现
      • Promise.catch 方法实现
      • Promise.all 方法实现
      • Promise.race 方法实现
      • Promise.reject 方法实现
      • Promise.resolve 方法实现
    • 结果
  • Axios源码分析
  • vueRouter源码分析
  • Webpack原理
  • 阅读《重构:改善既有代码的设计》笔记
  • 笔记
coderly
2020-06-27

分析Promise实现

# 分析 Promise 内部实现

在介绍Promise之前,首先我们举一个栗子,看下面代码

function success(message) {
  console.log(message)
}
function fail(message) {
  console.log(message)
}
function readFile(success, fail) {
  console.log('文件读取启动了...')
  setTimeout(() => {
    if (+new Date() % 2 === 0) {
      success('success:文件读取成功了')
    } else {
      fail('fail:文件读取失败了')
    }
  }, 1000)
}
readFile(success, fail) // 执行 readFile 函数
console.log('end...')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

输出结果:
Promise 图片

【分析】

  • 这里我们定义了一个 readFile 函数,里面用一个 setTimeout 定时器模拟读取文件得异步操作
  • 而后定时器里分情况调用 success 或 fail 函数
  • 首先我们需要注意得是,在这里如果我们需要启动定时器,必须执行 readFile() ,同时也必须把回调函数一起传进去
  • 也就是说,如果 readFile 函数内部已经开始执行得时候
  • 如果要有结果,此时必定有 success 和 fail 函数
  • 简单概括的话,就是在有结果输出的情况下, readFile 函数内部元素压入调用栈开始执行时, success 和 fail 回调函数 必定存在---即已经定义好了
  • 至于为什么会用这个栗子开头,请接着往下看....

# 初识 Promise

举个栗子,看下面的代码:

let file = new Promise((resolve, reject) => {
  console.log('promise 读取文件开始了...')
  setTimeout(() => {
    if (+new Date() % 2 === 0) {
      resolve('success:文件读取成功了')
    } else {
      reject('fail:文件读取失败了')
    }
  }, 1000)
})
setTimeout(() => {
  // 3秒之后开始传入回调函数
  file
    .then((res) => {
      console.log(res)
    })
    .catch((err) => {
      console.log(err)
    })
}, 3000)
console.log('end...')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

输出结果:
Promise 图片

【分析】

  • 在第一行代码,我们 new 了一个 Promise 对象
  • 里面用了一个 1s 定时器 模拟 文件读取 的异步操作
  • 看输出结果,第一句输出的是 Promise 内部的第一行代码,也就是说,new Promise 对象时,内部已经开始执行了,
  • 1s之后,分情况调用 resolve 或 reject 函数
  • 我们注意到,此时我们还没有传入回调函数,resolve 和 reject 只是我们 new Promise 时定义的形式参数
  • 3s 后,我们开始传入回调函数,这时,我们在 3s 后传入的回调函数执行了并且出现了结果

【思考】我们回想一开始举的例子

  1. readFile 函数执行的时候,此时回调函数已经定义好了,并且作为参数传入了 readFile 函数
  2. new Promise 的时候,内部已经开始执行,此时我们并未传入回调函数
  3. 3s 之后,我们才传入回调函数,神奇的是最后有结果输出

【提示】这样一对比,你是不是发现了什么

  1. Promise 一 创建对象 内部开始执行,此时我们没有传入回调函数
  2. 未来的某段时间里,我们传入回调函数,回调函数可能会执行并且可以取到结果

【分析总结】

  • 在 Promise 内部,我们 new 的时候传入的函数应该立即执行
  • 因为在未来的某段时间传入回调函数可以取到结果,所以 Promise 内部应该有一个变量将 结果 缓存起来了

# 手动实现 Promise

  • 我们通过 new 创建 Promise 对象,所以 Promise 应该是一个函数,同时传入一个函数作为参数,该函数立即执行
  • Promise 有 3 种状态:pending、fulfilled、rejected(等待中、已成功、已失败),并且状态只能pending -> fulfilled (等待中 -> 已成功)或 pending -> rejected(等待中 -> 已失败),改变之后状态不能再次变化
  • 内部有变量存储 失败 或 成功 的结果,这里定义为存储变量为 data
  • 同时 Promise 可以链式调用传入回调函数,因此还存在变量保存回调函数集合,这里定义 保存成功的变量 onResolvedCallback,保存失败的变量 onRejectedCallback
let myPromise = (function() {
  // 定义变量保存状态的名字
  const PENDING = 'pending' //初始状态
  const FULFILLED = 'fulfilled' // 成功状态
  const REJECTED = 'rejected' // 成功
  function Promise(executor) {
    this.status = PENDING // 定义变量保存 状态,初始时为 pending
    this.data = undefined // 定义变量保存 结果
    this.onResolvedCallback = [] // resolve时的回调函数集合
    this.onRejectedCallback = [] // reject时的回调函数集合 // 考虑到执行executor的过程中有可能出错,所以我们用try/catch块给包起来,并且在出错后以catch捕获到的值reject掉这个Promise
    try {
      // 因为new Promise对象时传入一个函数,该函数立即执行
      executor(resolve, reject) // 执行executor
    } catch (e) {
      reject(e)
    }
  }
  return Promise
})()
let p = new myPromise(function(resolve, reject) {
  setTimeout(() => {
    if (+new Date() % 2 === 0) {
      resolve('success:文件读取成功了')
    } else {
      reject('fail:文件读取失败了')
    }
  }, 1000)
})
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

输出结果
Promise 图片
因为我们在内部调用了 resolve 和 reject , 这两个变量在函数内部我们没有定义,所以出错。那我们在内部定义的这两个函数需要处理什么呢?

  • resolve 应该取状态变为 成功 的 结果,reject 应该取状态变为 失败 的结果。

继续完善代码

let myPromise = (function() {
  // 定义变量保存状态的名字
  const PENDING = 'pending' //初始状态
  const FULFILLED = 'fulfilled' // 成功状态
  const REJECTED = 'rejected' // 成功
  function Promise(executor) {
    this.status = PENDING // 定义变量保存 状态,初始时为 pending
    this.data = undefined // 定义变量保存 结果
    this.onResolvedCallback = [] // resolve时的回调函数集合
    this.onRejectedCallback = [] // reject时的回调函数集合
    function resolve(result) {
      if (this.status === PENDING) {
        // 状态只能是 pending, 才可以执行下面的代码
        this.status = FULFILLED // 因为调用 resolve,所以是成功的,所以状态变为 fulfilled
        this.data = result // 保存 成功 的结果 // 开始给 谁想要当前 成功的 结果,就执行他们的函数,并且将 成功 的结果传给他们
        this.onResolvedCallback.forEach((cb) => cb(this.data))
      }
    }
    function reject(reason) {
      // 同上
      if (this.status === PENDING) {
        this.status = REJECTED
        this.data = reason
        this.onRejectedCallback.forEach((cb) => cb(this.data))
      }
    } // 考虑到执行executor的过程中有可能出错,所以我们用try/catch块给包起来,并且在出错后以catch捕获到的值reject掉这个Promise
    try {
      // 因为new Promise对象时传入一个函数,该函数立即执行
      executor(resolve, reject) // 执行executor
    } catch (e) {
      reject(e)
    }
  }
  return Promise
})()
let p = new myPromise(function(resolve, reject) {
  setTimeout(() => {
    if (+new Date() % 2 === 0) {
      resolve('success:文件读取成功了')
    } else {
      reject('fail:文件读取失败了')
    }
  }, 1000)
})
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

到这一步,我们刚才分析的内容大部分完成了
如果我们 MDN 上搜索 Promise
Promise 图片

  • 我们发现 then、catch、finally 是 Promise 类的实例方法
  • all、race、reject 、resolve 是 Promise 类的静态方法
  • 所以我们根据分析,可以得出如下的 结构
Promise.prototype.then = function() {}
Promise.prototype.catch = function() {}
Promise.all = function() {}
Promise.race = function() {}
Promise.reject = function() {}
Promise.resolve = function() {}
1
2
3
4
5
6

# Promise.then 方法实现

  • Promise.then 接受两个参数,一个为 成功状态 的回调函数,一个为 失败状态 的回调函数
  • 同时我们可以不传回调函数,这时直接取 上一个处理的结果,不做处理,直接传递到 下一个

# 讲解

  • 首先,then 可以链式调用,所以每次都需要返回一个 Promise 对象
 Promise.prototype.then = function (onFulfilled, onRejected) {
      return new Promise(function (resolve, reject) {
      }
 }
1
2
3
4
  • 我们通过前面的分析,已经知道 then 里面的回调函数可以 在不同时间段给出,此时,当前这个 promise 可能出现 3 种状态 (等待中、已成功、已失败),所以分 3 种情况 处理
Promise.prototype.then = function(onFulfilled, onRejected) {
  return new Promise(function(resolve, reject) {
    if (self.status == FULFILLED) {
      //  已成功
    }
    if (self.status == REJECTED) {
      // 已失败
    }
    if (self.status === PENDING) {
      // 等待中
    }
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
  • 接下来我们分析,在这 3 种情况下应该做什么
# 已成功
  • 因为 状态已经变成了 已成功,所以存储了 成功的结果,我们将 成功的结果 作为参数传递给 onFulfilled 回调函数并执行
  • 因为 返回的 promise 的状态由 onFulfilled 回调函数执行的结果决定
  • 所以我们开始分析 onFulfilled 可能有什么样的结果
    1. 如果抛出异常,return  的  Promise  就会失败,结果   就是  error
    2. 如果回调函数返回不是  Promise,return  的  Promise  就会成功,value  就是返回的值
    3. 如果回调函数返回是  Promise,return  的  Promise  结果就是这个  Promise  的结果
  • 上面 3 种 结果是什么意思呢?我们以下面的栗子来说明
var p1 = new Promise()

// 1. 如果抛出异常,`return` 的 `Promise` 就会失败,结果 就是 `error`
p1.then(() => {
  // 就是有人会这么直接抛出异常,所以 p1 return 的 Promise 状态应该是 已失败
  throw 233
})

//  2. 如果回调函数返回不是 `Promise`,`return` 的 `Promise` 就会成功,`value` 就是返回的值
p1.then(() => {
  // 直接 return 一个 值,因为没有抛出异常,所以不是 已失败状态,同时 因为有了结果,所以不是 等待中,最后return 的 Promise 只能是 已成功 状态,
  return 1433
})
// 3. 如果回调函数返回是 `Promise`,`return` 的 `Promise` 结果就是这个 `Promise` 的结果
p1.then(() => {
  // 因为 返回 了 一个 Promise,所以当前状态无法确定,只能通过 返回的 这个 `Promise`  的最后状态来确定
  return new Promise(() => {})
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 根据 分析,我们初步实现 已成功 的 内容,因为要用到 Promise 的 存储的结果 data,所以我们定义一个变量self= this
Promise.prototype.then = function(onFulfilled, onRejected) {
  let self = this
  return new Promise(function(resolve, reject) {
    if (self.status == FULFILLED) {
      //  已成功
      setTimeout(() => {
        try {
          // 获取 回调函数执行的结果
          var _result = onFulfilled(self.data)
          if (_result instanceof Promise) {
            // 3. 如果回调函数返回是 `Promise`,`return` 的 `Promise` 结果就是这个 `Promise` 的结果
            _result.then(
              (res) => {
                resolve(res)
              },
              (err) => {
                reject(err)
              }
            )
          } else {
            //  2. 如果回调函数返回不是 `Promise`,`return` 的 `Promise` 就会成功,`value` 就是返回的值
            resolve(_result)
          }
        } catch (e) {
          // 1. 如果抛出异常,`return` 的 `Promise` 就会失败,结果 就是 `error`
          reject(e)
        }
      })
    }
    if (self.status == REJECTED) {
      // 已失败
    }
    if (self.status === PENDING) {
      // 等待中
    }
  })
}
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
# 问题:为什么 then回调函数必须设置为 setTimeout 的回调?
setTimeout(() => {
  // 保证返回的 Promise 是异步
  try {
    var _result = onFulfilled(self.data)
    if (_result instanceof Promise) {
      _result.then(
        (res) => {
          resolve(res)
        },
        (err) => {
          reject(err)
        }
      )
    } else {
      resolve(_result)
    }
  } catch (e) {
    reject(e)
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • 保证返回的 Promise 是异步
  • (这个部分,下次更新)
# 已失败
  • 分析的思路和结果与上面的差不多,不做过多分析
  • 需要注意的是此时的  _result = onRejected(self.data) ,调用失败的回调函数
# 等待中
  • 因为当前 Promise 的状态是 进行中, 所以我们无法得知最后的状态是
  • 我们得等到 Promise 的 最后状态确定了 ,才能 知道 是调用 onFulfilled 还是 onRejected
  • 这时候我们通过发布订阅模式,将当前传入的回调函数都保存起来,等到有了结果再进行通知,并把最后状态的结果传给回调函数
Promise.prototype.then = function(onFulfilled, onRejected) {
  let self = this
  return new Promise(function(resolve, reject) {
    if (self.status == FULFILLED) {
      //  已成功
      setTimeout(() => {
        try {
          // 获取 回调函数执行的结果
          var _result = onFulfilled(self.data)
          if (_result instanceof Promise) {
            // 3. 如果回调函数返回是 `Promise`,`return` 的 `Promise` 结果就是这个 `Promise` 的结果
            _result.then(
              (res) => {
                resolve(res)
              },
              (err) => {
                reject(err)
              }
            )
          } else {
            //  2. 如果回调函数返回不是 `Promise`,`return` 的 `Promise` 就会成功,`value` 就是返回的值
            resolve(_result)
          }
        } catch (e) {
          // 1. 如果抛出异常,`return` 的 `Promise` 就会失败,结果 就是 `error`
          reject(e)
        }
      })
    }
    if (self.status == REJECTED) {
      // 已失败
      setTimeout(() => {
        try {
          var _result = onRejected(self.data)
          if (_result instanceof Promise) {
            _result.then(
              (res) => {
                resolve(res)
              },
              (err) => {
                reject(err)
              }
            )
          } else {
            resolve(_result)
          }
        } catch (e) {
          reject(e)
        }
      })
    }
    if (self.status === PENDING) {
      // 等待中
      self.onResolvedCallback.push(function() {
        setTimeout(() => {
          try {
            var _result = onFulfilled(self.data)
            if (_result instanceof Promise) {
              _result.then(
                (res) => {
                  resolve(res)
                },
                (err) => {
                  reject(err)
                }
              )
            } else {
              resolve(_result)
            }
          } catch (e) {
            reject(e)
          }
        })
      })
      self.onRejectedCallback.push(function() {
        setTimeout(() => {
          try {
            var _result = onRejected(self.data)
            if (_result instanceof Promise) {
              _result.then(
                (res) => {
                  resolve(res)
                },
                (err) => {
                  reject(err)
                }
              )
            } else {
              resolve(_result)
            }
          } catch (e) {
            reject(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
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
  • 我们发现有 四个 地方的内容我们重复写了 四遍,所以提取出来就变成了
Promise.prototype.then = function(onFulfilled, onRejected) {
  let self = this
  return new Promise(function(resolve, reject) {
    // 根据指定回调函数处理,根据执行结果,改变 return 的 promise 的状态
    function handle(callback) {
      try {
        var _result = callback(self.data)
        if (_result instanceof Promise) {
          _result.then(
            (res) => {
              resolve(res)
            },
            (err) => {
              reject(err)
            }
          )
        } else {
          resolve(_result)
        }
      } catch (e) {
        reject(e)
      }
    }
    if (self.status == FULFILLED) {
      setTimeout(() => {
        handle(onFulfilled)
      })
    }
    if (self.status == REJECTED) {
      // 如果当前是 resolved 状态,异步执行 onRejected 并改变 return 的 promise 状态
      setTimeout(() => {
        handle(onRejected)
      })
    }
    if (self.status === PENDING) {
      self.onResolvedCallback.push(function() {
        setTimeout(() => {
          handle(onFulfilled)
        })
      })
      self.onRejectedCallback.push(function() {
        setTimeout(() => {
          handle(onRejected)
        })
      })
    }
  })
}
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
# 透传
  • 由于我们调用 .then 方法时,可以一个回调函数都不传,此时应当不对最后状态的结果进行处理,直接传递到下一个 Promise
  • 请始终记得,只要没有手动对状态确定的 Promise 的结果进行 过处理,Promise 的状态就不会再改变
Promise.prototype.then = function(onFulfilled, onRejected) {
  onFulfilled =
    typeof onFulfilled == 'function' ? onFulfilled : (value) => value
  onRejected =
    typeof onRejected == 'function'
      ? onRejected
      : (reason) => {
          throw reason
        }
  let self = this
  return new Promise(function(resolve, reject) {
    // 根据指定回调函数处理,根据执行结果,改变 return 的 promise 的状态
    function handle(callback) {
      try {
        var _result = callback(self.data)
        if (_result instanceof Promise) {
          _result.then(
            (res) => {
              resolve(res)
            },
            (err) => {
              reject(err)
            }
          )
        } else {
          resolve(_result)
        }
      } catch (e) {
        reject(e)
      }
    }
    if (self.status == FULFILLED) {
      setTimeout(() => {
        handle(onFulfilled)
      })
    }
    if (self.status == REJECTED) {
      // 如果当前是 resolved 状态,异步执行 onRejected 并改变 return 的 promise 状态
      setTimeout(() => {
        handle(onRejected)
      })
    }
    if (self.status === PENDING) {
      self.onResolvedCallback.push(function() {
        setTimeout(() => {
          handle(onFulfilled)
        })
      })
      self.onRejectedCallback.push(function() {
        setTimeout(() => {
          handle(onRejected)
        })
      })
    }
  })
}
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
  • 通过以上分析,我们已经实现了 .then 方法

# Promise.catch 方法实现

  • catch 方法,传入一个失败的回调函数,因为需要获取 失败的结果,所以我们直接调用当前 Promise 的 then 方法来获取 失败的结果
  • 同时调用了 .catch 之后,还是返回一个 Promise 对象,并且 下一个 Promise 的状态由 .catch 的回调函数 返回值确定
  • 在这里人们会存在的一个误解是:调用 .catch 之后,以后的 Promise 状态都是 已失败,这是错误的
  • 你需要时刻记得的是:只要你没有用回调函数处理过 已失败 的结果,之后的 Promise 状态就是 已失败,只要你 用回调函数处理了 已失败的结果,之后的 Promise 状态就根据你 回调函数的 结果来 确定。
Promise.prototype.catch = function(onRejected) {
  return this.then(undefined, onRejected)
}
1
2
3

# Promise.all 方法实现

  • Promise.all 方法传入一个数组,当数组中有一个 结果是 已失败 时,最后结果就是 已失败,只有当数组中的 所有 结果都是 成功时,该方法才会被确定为 已成功 的状态
  • 已成功 的 结果是一个数组
  • 需要注意的是,已成功 的 结果数组,和 Promise.all 传入的数组是相对应得
  • 也就是说,传入的第 2 个 是 已成功 数组 的 第 2 个 结果
  • 这里我们可以借鉴 我们常遇到的 保证多个ajax 请求都返回了结果 的解决 办法。
  • 我们通过一个变量(successNum)来保存 已成功 的数量,如果最后该变量的值 和 传入的数组 长度 一样,那就说明 传入的 数组 所有结果都是 已成功
  • 遇到 一个执行结果是 已失败,直接返回 已失败 的状态

【分析】传入的数组可能的情况

  • [1, '233', new Promise()]
  • 一是 字符串或数字
  • 二是 Promise 对象
Promise.all = function(promises) {
  let len = promises.length
  let successNum = 0
  let _result = []
  return new Promise((resolve, reject) => {
    promises.forEach((p, i) => {
      try {
        // 针对 Promise 对象
        if (p instanceof Promise) {
          p.then(
            (res) => {
              successNum++
              _result[i] = res
              if (successNum === len) {
                resolve(_result)
              }
            },
            (err) => {
              reject(err)
            }
          )
        } else {
          // 非 Promise 对象
          successNum++
          _result[i] = p
          if (successNum === len) {
            resolve(_result)
          }
        }
      } catch (err) {
        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
24
25
26
27
28
29
30
31
32
33
34
35

# Promise.race 方法实现

  • Promise.race , 传入的是一个数组,谁先有结果,返回的 Promise 的状态就是该结果的 状态
  • 该方法和 Promise.all 相比,不需要变量 保存 谁已经执行了,只需要遇到哪个执行完成了,直接返回和其结果一样的状态
Promise.race = function(promises) {
  return new Promise((resolve, reject) => {
    promises.forEach((p, i) => {
      try {
        if (p instanceof Promise) {
          p.then(
            (res) => {
              resolve(res)
            },
            (err) => {
              reject(err)
            }
          )
        } else {
          resolve(p)
        }
      } catch (err) {
        reject(err)
      }
    })
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# Promise.reject 方法实现

  • 该方法返回一个 已失败 状态 的 Promise
  • 直接通过新建一个 Promise 对象,只传入第二个参数,返回一个 已失败 的 Promise
Promise.reject = function(rejected) {
  return new Promise((undefined, reject) => {
    reject(rejected)
  })
}
1
2
3
4
5

# Promise.resolve 方法实现

  • 该方法返回一个 已成功 状态的 Promise
  • 我们同样通过直接返回一个 Promise 对象来 获取 返回成功的 状态
  • 这里需要注意的是:因为是返回 一个 已成功 的状态,但是我们并不能保证 用户传入的 结果最后就是 已成功 的状态
  • 该方法和 Promise.reject 不同
  • 用户如果传入了一个 Promise 对象 作为参数,那我们应该 取 传入的参数结果和状态作为 当前 Promise 最后返回的结果和状态
Promise.resolve = function(result) {
  return new Promise((resolve, reject) => {
    try {
      // 如果传入的是一个 Promise 类型的变量,取它的状态和结果作为  Promise.resolve 的状态和结果
      if (result instanceof Promise) {
        result.then(
          (res) => {
            resolve(res)
          },
          (err) => {
            reject(err)
          }
        )
      }
      resolve(result)
    } catch (e) {
      reject(e)
    }
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 结果

  • 发一个最终版和测试用例
const _Promise = (function() {
  const PENDING = 'pending' //初始状态
  const FULFILLED = 'fulfilled' // 成功状态
  const REJECTED = 'rejected' // 失败状态
  function Promise(executor) {
    var self = this
    self.status = PENDING
    self.data = undefined
    self.onResolvedCallback = []
    self.onRejectedCallback = []
    function resolve(result) {
      if (self.status === PENDING) {
        self.status = FULFILLED
        self.data = result
        self.onResolvedCallback.forEach((cb) => cb(self.data))
      }
    }
    function reject(reason) {
      if (self.status === PENDING) {
        self.status = REJECTED
        self.data = reason
        self.onRejectedCallback.forEach((cb) => cb(self.data))
      }
    }
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  Promise.prototype.then = function(onFulfilled, onRejected) {
    onFulfilled =
      typeof onFulfilled == 'function' ? onFulfilled : (value) => value
    onRejected =
      typeof onRejected == 'function'
        ? onRejected
        : (reason) => {
            throw reason
          }
    let self = this
    return new Promise(function(resolve, reject) {
      // 根据指定回调函数处理,根据执行结果,改变 return 的 promise 的状态
      function handle(callback) {
        try {
          var _result = callback(self.data)
          if (_result instanceof Promise) {
            _result.then(
              (res) => {
                resolve(res)
              },
              (err) => {
                reject(err)
              }
            )
          } else {
            resolve(_result)
          }
        } catch (e) {
          reject(e)
        }
      }
      if (self.status == FULFILLED) {
        setTimeout(() => {
          handle(onFulfilled)
        })
      }
      if (self.status == REJECTED) {
        // 如果当前是 resolved 状态,异步执行 onRejected 并改变 return 的 promise 状态
        setTimeout(() => {
          handle(onRejected)
        })
      }
      if (self.status === PENDING) {
        self.onResolvedCallback.push(function() {
          setTimeout(() => {
            handle(onFulfilled)
          })
        })
        self.onRejectedCallback.push(function() {
          setTimeout(() => {
            handle(onRejected)
          })
        })
      }
    })
  }
  Promise.prototype.catch = function(onRejected) {
    return this.then(undefined, onRejected)
  }
  Promise.all = function(promises) {
    let len = promises.length
    let successNum = 0
    let _result = []
    return new Promise((resolve, reject) => {
      promises.forEach((p, i) => {
        try {
          if (p instanceof Promise) {
            p.then(
              (res) => {
                successNum++
                _result[i] = res
                if (successNum === len) {
                  resolve(_result)
                }
              },
              (err) => {
                reject(err)
              }
            )
          } else {
            successNum++
            _result[i] = p
            if (successNum === len) {
              resolve(_result)
            }
          }
        } catch (err) {
          reject(err)
        }
      })
    })
  }
  Promise.race = function(promises) {
    return new Promise((resolve, reject) => {
      promises.forEach((p, i) => {
        try {
          if (p instanceof Promise) {
            p.then(
              (res) => {
                resolve(res)
              },
              (err) => {
                reject(err)
              }
            )
          } else {
            resolve(p)
          }
        } catch (err) {
          reject(err)
        }
      })
    })
  }
  Promise.reject = function(rejected) {
    return new Promise((undefined, reject) => {
      reject(rejected)
    })
  }
  Promise.resolve = function(result) {
    return new Promise((resolve, reject) => {
      try {
        if (result instanceof Promise) {
          result.then(
            (res) => {
              resolve(res)
            },
            (err) => {
              reject(err)
            }
          )
        }
        resolve(result)
      } catch (e) {
        reject(e)
      }
    })
  }
  return Promise
})()
let p1 = new _Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p1 ---> resolve')
  }, 1000)
})
let p2 = new _Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2 ---> resolve')
  }, 500)
})
let p3 = new _Promise((resolve, reject) => {
  setTimeout(() => {
    reject('p3 ---> reject')
  }, 1500)
})
_Promise
  .all([p1, p2, 120, 'hello', p3])
  .then((res) => {
    console.log('resolve', res)
  })
  .then(
    () => {},
    (err) => {
      console.log('err', err)
      throw ''
    }
  )
  .then(
    (res) => {
      console.log('res', res)
    },
    (err) => {
      console.log('err', 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
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

【输出结果】

err p3 ---> reject
err
1
2
#JavaScript#Promise
上次更新: 2021/09/13, 15:11:59
Axios源码分析

Axios源码分析→

最近更新
01
css
09-13
02
html
09-13
03
README
09-13
更多文章>
Theme by Vdoing | Copyright © 2021-2021 coderly | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式