1、前言

本篇文章,默认你已经知道什么是 Promise ,然后我会带你一步步的实现一个简易的 Promise。将会以循序渐进的方式,分步骤实现。

本文章相关代码地址:https://github.com/layouwen/blog_demo_lpromise

如果本文章对你有所帮助,请不要吝啬你的 Start 哦~

2、三种状态

此处代码,点击这里

Promise 它一共会有三种状态:

  1. pending
  2. fulfilled
  3. rejected

下面我们自己实现一个类,默认为 pending 状态,通过调用 resolve 或者 reject 改变其状态

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  6. }
  7. #resolve(res) {
  8. this['[[PromiseState]]'] = 'fulfilled'
  9. this['[[PromiseResult]]'] = res
  10. }
  11. #reject(err) {
  12. this['[[PromiseState]]'] = 'reject'
  13. this['[[PromiseResult]]'] = err
  14. }
  15. }
  16. console.log(new LPromise((resolve, reject) => console.log('pending'))) // pending 状态
  17. const l1 = new LPromise((resolve, reject) => {
  18. resolve('我调用了resolve')
  19. })
  20. console.log(l1) // fulfilled 状态
  21. const l2 = new LPromise((resolve, reject) => {
  22. reject('我调用了reject')
  23. })
  24. console.log(l2) // rejected 状态

3、实现 then 参数回调

此处代码,点击这里

返回的 Promise ,可以通过使用 then 传递成功和失败的回调。

通过 then 接收了两个回调。实现了分别调用回调的内容。但是发现,他们两个都会执行。

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  6. }
  7. #resolve(res) {
  8. this['[[PromiseState]]'] = 'fulfilled'
  9. this['[[PromiseResult]]'] = res
  10. }
  11. #reject(err) {
  12. this['[[PromiseState]]'] = 'reject'
  13. this['[[PromiseResult]]'] = err
  14. }
  15. /* new content start */
  16. then(onResolve, onReject) {
  17. onResolve()
  18. onReject()
  19. }
  20. /* new content end */
  21. }
  22. const l1 = new LPromise((resolve, reject) => resolve())
  23. l1.then(
  24. res => console.log('res'),
  25. err => console.log('err')
  26. )

对执行时机进行调整。使其在调用 resolve 或 reject 才执行相关的回调

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  6. }
  7. #resolve(res) {
  8. this['[[PromiseState]]'] = 'fulfilled'
  9. this['[[PromiseResult]]'] = res
  10. /* new content start */
  11. this.cbResolve() // 报错
  12. /* new content end */
  13. }
  14. #reject(err) {
  15. this['[[PromiseState]]'] = 'reject'
  16. this['[[PromiseResult]]'] = err
  17. /* new content start */
  18. this.cbReject() // 报错
  19. /* new content end */
  20. }
  21. then(onResolve, onReject) {
  22. /* new content start */
  23. this.cbResolve = onResolve
  24. this.cbReject = onReject
  25. /* new content end */
  26. }
  27. }
  28. const l1 = new LPromise((resolve, reject) => resolve())
  29. l1.then(
  30. res => console.log('res'),
  31. err => console.log('err')
  32. )

改装后,发现 resolve 和 reject 的执行时间比 then 的回调要快。导致无法执行 then 中的回调。我们需要对 resolve 和 reject 中执行回调的部分进行 延迟执行。可以使用 setTimeout 进行延迟

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  6. }
  7. #resolve(res) {
  8. this['[[PromiseState]]'] = 'fulfilled'
  9. this['[[PromiseResult]]'] = res
  10. /* new content start */
  11. setTimeout(() => this.cbResolve())
  12. /* new content end */
  13. }
  14. #reject(err) {
  15. this['[[PromiseState]]'] = 'reject'
  16. this['[[PromiseResult]]'] = err
  17. /* new content start */
  18. setTimeout(() => this.cbReject())
  19. /* new content end */
  20. }
  21. then(onResolve, onReject) {
  22. this.cbResolve = onResolve
  23. this.cbReject = onReject
  24. }
  25. }
  26. const l1 = new LPromise((resolve, reject) => resolve())
  27. l1.then(
  28. res => console.log('res'),
  29. err => console.log('err')
  30. )

考虑到 微任务 和 宏任务。我们可以使用 MutationObserver 替代 setTimeout

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  6. }
  7. #resolve(res) {
  8. this['[[PromiseState]]'] = 'fulfilled'
  9. this['[[PromiseResult]]'] = res
  10. /* new content start */
  11. const run = () => this.cbResolve()
  12. const ob = new MutationObserver(run)
  13. ob.observe(document.body, { attributes: true })
  14. document.body.setAttribute('lpromise', 'layouwen')
  15. /* new content end */
  16. }
  17. #reject(err) {
  18. this['[[PromiseState]]'] = 'reject'
  19. this['[[PromiseResult]]'] = err
  20. /* new content start */
  21. const run = () => this.cbReject()
  22. const ob = new MutationObserver(run)
  23. ob.observe(document.body, { attributes: true })
  24. document.body.setAttribute('lpromise', 'layouwen')
  25. /* new content end */
  26. }
  27. then(onResolve, onReject) {
  28. this.cbResolve = onResolve
  29. this.cbReject = onReject
  30. }
  31. }
  32. const l1 = new LPromise((resolve, reject) => resolve())
  33. l1.then(
  34. res => console.log('res'),
  35. err => console.log('err')
  36. )

4、链式调用

此处代码,点击这里

在原本的 Promise 中。我们是可以使用 then 链式调用。意味着每个 then 都返回一个新的 Promise

因为支持链式。所以我们之前的 cbResolvecbReject 就不能单单保存一个回调。要改回一个数组,将每一个 then 中的回调。都保存到回调队列中。等待调用 resolve 或者 reject 后才执行所有回调函数。

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. /* new content start */
  6. this.cbResolveQueue = []
  7. this.cbRejectQueue = []
  8. /* new content end */
  9. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  10. }
  11. #resolve(res) {
  12. this['[[PromiseState]]'] = 'fulfilled'
  13. this['[[PromiseResult]]'] = res
  14. /* new content start */
  15. const run = () => {
  16. let cbFn
  17. while ((cbFn = this.cbResolveQueue.shift())) {
  18. cbFn && cbFn()
  19. }
  20. }
  21. /* new content end */
  22. const ob = new MutationObserver(run)
  23. ob.observe(document.body, { attributes: true })
  24. document.body.setAttribute('lpromise', 'layouwen')
  25. }
  26. #reject(err) {
  27. this['[[PromiseState]]'] = 'reject'
  28. this['[[PromiseResult]]'] = err
  29. /* new content start */
  30. const run = () => {
  31. let cbFn
  32. while ((cbFn = this.cbRejectQueue.shift())) {
  33. cbFn && cbFn()
  34. }
  35. }
  36. /* new content end */
  37. const ob = new MutationObserver(run)
  38. ob.observe(document.body, { attributes: true })
  39. document.body.setAttribute('lpromise', 'layouwen')
  40. }
  41. then(onResolve, onReject) {
  42. /* new content start */
  43. return new LPromise((resolve, reject) => {
  44. const cbResolve = () => {
  45. onResolve && onResolve()
  46. resolve()
  47. }
  48. this.cbResolveQueue.push(cbResolve)
  49. const cbReject = () => {
  50. onReject && onReject()
  51. reject()
  52. }
  53. this.cbRejectQueue.push(cbReject)
  54. })
  55. /* new content end */
  56. }
  57. }
  58. const l1 = new LPromise((resolve, reject) => resolve())
  59. l1.then(
  60. res => console.log('res'),
  61. err => console.log('err')
  62. ).then(
  63. res => console.log('res'),
  64. err => console.log('err')
  65. )

此时我们已经完成了链式调用,但是我们会发现,此时如果返回一个新的 Promise ,却无法获取 Promise 的结果。所以我们得加一些判断条件。我们也会发现,此时此刻我们无法接收到 reserr 的参数。所以我们也要完善一下参数传递问题。

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. this.cbResolveQueue = []
  6. this.cbRejectQueue = []
  7. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  8. }
  9. #resolve(res) {
  10. this['[[PromiseState]]'] = 'fulfilled'
  11. this['[[PromiseResult]]'] = res
  12. const run = () => {
  13. let cbFn
  14. while ((cbFn = this.cbResolveQueue.shift())) {
  15. /* new content start */
  16. cbFn && cbFn(res)
  17. /* new content end */
  18. }
  19. }
  20. const ob = new MutationObserver(run)
  21. ob.observe(document.body, { attributes: true })
  22. document.body.setAttribute('lpromise', 'layouwen')
  23. }
  24. #reject(err) {
  25. this['[[PromiseState]]'] = 'reject'
  26. this['[[PromiseResult]]'] = err
  27. const run = () => {
  28. let cbFn
  29. while ((cbFn = this.cbRejectQueue.shift())) {
  30. /* new content start */
  31. cbFn && cbFn(err)
  32. /* new content end */
  33. }
  34. }
  35. const ob = new MutationObserver(run)
  36. ob.observe(document.body, { attributes: true })
  37. document.body.setAttribute('lpromise', 'layouwen')
  38. }
  39. then(onResolve, onReject) {
  40. return new LPromise((resolve, reject) => {
  41. /* new content start */
  42. const cbResolve = res => {
  43. const resolveRes = onResolve && onResolve(res)
  44. if (resolveRes instanceof LPromise) {
  45. resolveRes.then(resolve)
  46. } else {
  47. resolve(res)
  48. }
  49. }
  50. /* new content end */
  51. this.cbResolveQueue.push(cbResolve)
  52. /* new content start */
  53. const cbReject = err => {
  54. onReject && onReject(err)
  55. reject(err)
  56. }
  57. /* new content end */
  58. this.cbRejectQueue.push(cbReject)
  59. })
  60. }
  61. }
  62. const l1 = new LPromise((resolve, reject) => resolve('我是传入的 resolve 数据'))
  63. l1.then(
  64. res => {
  65. console.log('第一个then的res', res)
  66. return new LPromise((resolve, reject) => resolve('返回的Promise'))
  67. },
  68. err => console.log('第一个then的err', err)
  69. )
  70. .then(
  71. res => console.log('第二个then的res', res),
  72. err => console.log('第二个then的err', err)
  73. )
  74. .then(
  75. res => console.log('第三个then的res', res),
  76. err => console.log('第三个then的err', err)
  77. )

到现在我们已经实现了 then 的链式调用

5、实现 catch 方法

此处代码,点击这里

在调用 catch 的时候自动在回调队列中添加一个错误回调函数。

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. this.cbResolveQueue = []
  6. this.cbRejectQueue = []
  7. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  8. }
  9. #resolve(res) {
  10. this['[[PromiseState]]'] = 'fulfilled'
  11. this['[[PromiseResult]]'] = res
  12. const run = () => {
  13. let cbFn
  14. while ((cbFn = this.cbResolveQueue.shift())) {
  15. cbFn && cbFn(res)
  16. }
  17. }
  18. const ob = new MutationObserver(run)
  19. ob.observe(document.body, { attributes: true })
  20. document.body.setAttribute('lpromise', 'layouwen')
  21. }
  22. #reject(err) {
  23. this['[[PromiseState]]'] = 'reject'
  24. this['[[PromiseResult]]'] = err
  25. const run = () => {
  26. let cbFn
  27. while ((cbFn = this.cbRejectQueue.shift())) {
  28. cbFn && cbFn(err)
  29. }
  30. }
  31. const ob = new MutationObserver(run)
  32. ob.observe(document.body, { attributes: true })
  33. document.body.setAttribute('lpromise', 'layouwen')
  34. }
  35. then(onResolve, onReject) {
  36. return new LPromise((resolve, reject) => {
  37. const cbResolve = res => {
  38. const resolveRes = onResolve && onResolve(res)
  39. if (resolveRes instanceof LPromise) {
  40. resolveRes.then(resolve)
  41. } else {
  42. resolve(res)
  43. }
  44. }
  45. this.cbResolveQueue.push(cbResolve)
  46. const cbReject = err => {
  47. onReject && onReject(err)
  48. reject(err)
  49. }
  50. this.cbRejectQueue.push(cbReject)
  51. })
  52. }
  53. /* new content start */
  54. catch(err) {
  55. this.then(undefined, err)
  56. }
  57. /* new content end */
  58. }
  59. const p1 = new LPromise((resolve, reject) => reject('我是p1的错误信息'))
  60. p1.then(res => console.log(res)).catch(err => console.log(err))

6、resolve 和 reject 静态方法

此处代码,点击这里

这两个静态方法比较简单。只需要返回一个固定状态的 Promise 即可。

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. this.cbResolveQueue = []
  6. this.cbRejectQueue = []
  7. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  8. }
  9. #resolve(res) {
  10. this['[[PromiseState]]'] = 'fulfilled'
  11. this['[[PromiseResult]]'] = res
  12. const run = () => {
  13. let cbFn
  14. while ((cbFn = this.cbResolveQueue.shift())) {
  15. cbFn && cbFn(res)
  16. }
  17. }
  18. const ob = new MutationObserver(run)
  19. ob.observe(document.body, { attributes: true })
  20. document.body.setAttribute('lpromise', 'layouwen')
  21. }
  22. #reject(err) {
  23. this['[[PromiseState]]'] = 'reject'
  24. this['[[PromiseResult]]'] = err
  25. const run = () => {
  26. let cbFn
  27. while ((cbFn = this.cbRejectQueue.shift())) {
  28. cbFn && cbFn(err)
  29. }
  30. }
  31. const ob = new MutationObserver(run)
  32. ob.observe(document.body, { attributes: true })
  33. document.body.setAttribute('lpromise', 'layouwen')
  34. }
  35. then(onResolve, onReject) {
  36. return new LPromise((resolve, reject) => {
  37. const cbResolve = res => {
  38. const resolveRes = onResolve && onResolve(res)
  39. if (resolveRes instanceof LPromise) {
  40. resolveRes.then(resolve)
  41. } else {
  42. resolve(res)
  43. }
  44. }
  45. this.cbResolveQueue.push(cbResolve)
  46. const cbReject = err => {
  47. onReject && onReject(err)
  48. reject(err)
  49. }
  50. this.cbRejectQueue.push(cbReject)
  51. })
  52. }
  53. /* new content start */
  54. static resolve(res) {
  55. return new LPromise(resolve => resolve(res))
  56. }
  57. static reject(err) {
  58. return new LPromise((undefined, reject) => reject(err))
  59. }
  60. /* new content end */
  61. }
  62. const p1 = LPromise.resolve('成功')
  63. console.log(p1)
  64. const p2 = LPromise.reject('失败')
  65. console.log(p2)

7、实现 finally 方法

此处代码,点击这里

这个与 catch 类似的实现,只需要保证不管成功还是失败都执行里面的回调。

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. this.cbResolveQueue = []
  6. this.cbRejectQueue = []
  7. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  8. }
  9. #resolve(res) {
  10. this['[[PromiseState]]'] = 'fulfilled'
  11. this['[[PromiseResult]]'] = res
  12. const run = () => {
  13. let cbFn
  14. while ((cbFn = this.cbResolveQueue.shift())) {
  15. cbFn && cbFn(res)
  16. }
  17. }
  18. const ob = new MutationObserver(run)
  19. ob.observe(document.body, { attributes: true })
  20. document.body.setAttribute('lpromise', 'layouwen')
  21. }
  22. #reject(err) {
  23. this['[[PromiseState]]'] = 'reject'
  24. this['[[PromiseResult]]'] = err
  25. const run = () => {
  26. let cbFn
  27. while ((cbFn = this.cbRejectQueue.shift())) {
  28. cbFn && cbFn(err)
  29. }
  30. }
  31. const ob = new MutationObserver(run)
  32. ob.observe(document.body, { attributes: true })
  33. document.body.setAttribute('lpromise', 'layouwen')
  34. }
  35. then(onResolve, onReject) {
  36. return new LPromise((resolve, reject) => {
  37. const cbResolve = res => {
  38. const resolveRes = onResolve && onResolve(res)
  39. if (resolveRes instanceof LPromise) {
  40. resolveRes.then(resolve)
  41. } else {
  42. resolve(res)
  43. }
  44. }
  45. this.cbResolveQueue.push(cbResolve)
  46. const cbReject = err => {
  47. onReject && onReject(err)
  48. reject(err)
  49. }
  50. this.cbRejectQueue.push(cbReject)
  51. })
  52. }
  53. catch(err) {
  54. this.then(undefined, err)
  55. }
  56. /* new content start */
  57. finally(callback) {
  58. this.then(callback, callback)
  59. }
  60. /* new content end */
  61. static resolve(res) {
  62. return new LPromise(resolve => resolve(res))
  63. }
  64. static reject(err) {
  65. return new LPromise((undefined, reject) => reject(err))
  66. }
  67. }
  68. const p1 = new LPromise((resolve, reject) => reject('我是p1的错误信息'))
  69. p1.then(
  70. res => console.log(res),
  71. err => console.log(err)
  72. ).finally(() => console.log('finally'))

8、实现 race 方法

此处代码,点击这里

race 就是返回最先执行成功的结果。不管是成功还是失败。这样我们只需要遍历该 Promise ,正常返回数据。谁先执行完成,谁先返回即可。注意要控制状态,防止返回多个结果。 race 只需要返回最快的一个结果。

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. this.cbResolveQueue = []
  6. this.cbRejectQueue = []
  7. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  8. }
  9. #resolve(res) {
  10. this['[[PromiseState]]'] = 'fulfilled'
  11. this['[[PromiseResult]]'] = res
  12. const run = () => {
  13. let cbFn
  14. while ((cbFn = this.cbResolveQueue.shift())) {
  15. cbFn && cbFn(res)
  16. }
  17. }
  18. const ob = new MutationObserver(run)
  19. ob.observe(document.body, { attributes: true })
  20. document.body.setAttribute('lpromise', 'layouwen')
  21. }
  22. #reject(err) {
  23. this['[[PromiseState]]'] = 'reject'
  24. this['[[PromiseResult]]'] = err
  25. const run = () => {
  26. let cbFn
  27. while ((cbFn = this.cbRejectQueue.shift())) {
  28. cbFn && cbFn(err)
  29. }
  30. }
  31. const ob = new MutationObserver(run)
  32. ob.observe(document.body, { attributes: true })
  33. document.body.setAttribute('lpromise', 'layouwen')
  34. }
  35. then(onResolve, onReject) {
  36. return new LPromise((resolve, reject) => {
  37. const cbResolve = res => {
  38. const resolveRes = onResolve && onResolve(res)
  39. if (resolveRes instanceof LPromise) {
  40. resolveRes.then(resolve)
  41. } else {
  42. resolve(res)
  43. }
  44. }
  45. this.cbResolveQueue.push(cbResolve)
  46. const cbReject = err => {
  47. onReject && onReject(err)
  48. reject(err)
  49. }
  50. this.cbRejectQueue.push(cbReject)
  51. })
  52. }
  53. catch(err) {
  54. this.then(undefined, err)
  55. }
  56. finally(callback) {
  57. this.then(callback, callback)
  58. }
  59. static resolve(res) {
  60. return new LPromise(resolve => resolve(res))
  61. }
  62. static reject(err) {
  63. return new LPromise((undefined, reject) => reject(err))
  64. }
  65. /* new content start */
  66. static race(promiseArr) {
  67. return new LPromise((resolve, reject) => {
  68. let isContinue = true
  69. promiseArr.forEach(promise => {
  70. promise.then(
  71. res => {
  72. if (isContinue) {
  73. isContinue = false
  74. resolve(res)
  75. }
  76. },
  77. err => {
  78. if (isContinue) {
  79. isContinue = false
  80. reject(err)
  81. }
  82. }
  83. )
  84. })
  85. })
  86. }
  87. /* new content end */
  88. }
  89. const p1 = new LPromise((resolve, reject) => setTimeout(() => resolve(1), 200))
  90. const p2 = new LPromise((resolve, reject) => setTimeout(() => reject(2), 1000))
  91. const p3 = new LPromise((resolve, reject) => setTimeout(() => resolve(3), 3000))
  92. LPromise.race([p1, p2, p3]).then(
  93. res => console.log('res', res),
  94. err => console.log('err', err)
  95. )

9、实现 all 方法

此处代码,点击这里

all 方法当所有 Promise 都成功时返回所有结果的数组,否则返回第一个失败的结果。我们只需要遍历该 Promise 数组。定义个变量存放当前 res 的长度。如果长度等于数组的长度,我们就 resolve 出去。否则发现第一个失败的时候,直接 reject

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. this.cbResolveQueue = []
  6. this.cbRejectQueue = []
  7. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  8. }
  9. #resolve(res) {
  10. this['[[PromiseState]]'] = 'fulfilled'
  11. this['[[PromiseResult]]'] = res
  12. const run = () => {
  13. let cbFn
  14. while ((cbFn = this.cbResolveQueue.shift())) {
  15. cbFn && cbFn(res)
  16. }
  17. }
  18. const ob = new MutationObserver(run)
  19. ob.observe(document.body, { attributes: true })
  20. document.body.setAttribute('lpromise', 'layouwen')
  21. }
  22. #reject(err) {
  23. this['[[PromiseState]]'] = 'reject'
  24. this['[[PromiseResult]]'] = err
  25. const run = () => {
  26. let cbFn
  27. while ((cbFn = this.cbRejectQueue.shift())) {
  28. cbFn && cbFn(err)
  29. }
  30. }
  31. const ob = new MutationObserver(run)
  32. ob.observe(document.body, { attributes: true })
  33. document.body.setAttribute('lpromise', 'layouwen')
  34. }
  35. then(onResolve, onReject) {
  36. return new LPromise((resolve, reject) => {
  37. const cbResolve = res => {
  38. const resolveRes = onResolve && onResolve(res)
  39. if (resolveRes instanceof LPromise) {
  40. resolveRes.then(resolve)
  41. } else {
  42. resolve(res)
  43. }
  44. }
  45. this.cbResolveQueue.push(cbResolve)
  46. const cbReject = err => {
  47. onReject && onReject(err)
  48. reject(err)
  49. }
  50. this.cbRejectQueue.push(cbReject)
  51. })
  52. }
  53. catch(err) {
  54. this.then(undefined, err)
  55. }
  56. finally(callback) {
  57. this.then(callback, callback)
  58. }
  59. static resolve(res) {
  60. return new LPromise(resolve => resolve(res))
  61. }
  62. static reject(err) {
  63. return new LPromise((undefined, reject) => reject(err))
  64. }
  65. static race(promiseArr) {
  66. return new LPromise((resolve, reject) => {
  67. let isContinue = true
  68. promiseArr.forEach(promise => {
  69. promise.then(
  70. res => {
  71. if (isContinue) {
  72. isContinue = false
  73. resolve(res)
  74. }
  75. },
  76. err => {
  77. if (isContinue) {
  78. isContinue = false
  79. reject(err)
  80. }
  81. }
  82. )
  83. })
  84. })
  85. }
  86. /* new content start */
  87. static all(promiseArr) {
  88. return new LPromise((resolve, reject) => {
  89. const resArr = []
  90. const length = promiseArr.length
  91. promiseArr.forEach(p => {
  92. p.then(
  93. res => {
  94. resArr.push(res)
  95. if (resArr.length === length) {
  96. resolve(resArr)
  97. }
  98. },
  99. err => reject(err)
  100. )
  101. })
  102. })
  103. }
  104. /* new content end */
  105. }
  106. const p1 = new LPromise((resolve, reject) => setTimeout(() => resolve(1), 200))
  107. const p2 = new LPromise((resolve, reject) => setTimeout(() => reject(2), 1000))
  108. const p3 = new LPromise((resolve, reject) => setTimeout(() => reject(3), 3000))
  109. LPromise.all([p1, p2, p3]).then(
  110. res => console.log('res', res),
  111. err => console.log('err', err)
  112. )

10、实现 allSettled 方法

此处代码,点击这里

该方法与 all 类似。只是这个方法不管成功或失败,只要该 Promise 数组执行完毕。就会返回所有结果。我们只需要判断执行过的 Promise 长度是否等于数组长度。当一致时就直接 resolve。并且每次执行的时候,将返回值以指定格式的对象保存到返回的 res 中。

  1. class LPromise {
  2. constructor(callbackFn) {
  3. this['[[PromiseState]]'] = 'pending'
  4. this['[[PromiseResult]]'] = undefined
  5. this.cbResolveQueue = []
  6. this.cbRejectQueue = []
  7. callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
  8. }
  9. #resolve(res) {
  10. this['[[PromiseState]]'] = 'fulfilled'
  11. this['[[PromiseResult]]'] = res
  12. const run = () => {
  13. let cbFn
  14. while ((cbFn = this.cbResolveQueue.shift())) {
  15. cbFn && cbFn(res)
  16. }
  17. }
  18. const ob = new MutationObserver(run)
  19. ob.observe(document.body, { attributes: true })
  20. document.body.setAttribute('lpromise', 'layouwen')
  21. }
  22. #reject(err) {
  23. this['[[PromiseState]]'] = 'reject'
  24. this['[[PromiseResult]]'] = err
  25. const run = () => {
  26. let cbFn
  27. while ((cbFn = this.cbRejectQueue.shift())) {
  28. cbFn && cbFn(err)
  29. }
  30. }
  31. const ob = new MutationObserver(run)
  32. ob.observe(document.body, { attributes: true })
  33. document.body.setAttribute('lpromise', 'layouwen')
  34. }
  35. then(onResolve, onReject) {
  36. return new LPromise((resolve, reject) => {
  37. const cbResolve = res => {
  38. const resolveRes = onResolve && onResolve(res)
  39. if (resolveRes instanceof LPromise) {
  40. resolveRes.then(resolve)
  41. } else {
  42. resolve(res)
  43. }
  44. }
  45. this.cbResolveQueue.push(cbResolve)
  46. const cbReject = err => {
  47. onReject && onReject(err)
  48. reject(err)
  49. }
  50. this.cbRejectQueue.push(cbReject)
  51. })
  52. }
  53. catch(err) {
  54. this.then(undefined, err)
  55. }
  56. finally(callback) {
  57. this.then(callback, callback)
  58. }
  59. static resolve(res) {
  60. return new LPromise(resolve => resolve(res))
  61. }
  62. static reject(err) {
  63. return new LPromise((undefined, reject) => reject(err))
  64. }
  65. static race(promiseArr) {
  66. return new LPromise((resolve, reject) => {
  67. let isContinue = true
  68. promiseArr.forEach(promise => {
  69. promise.then(
  70. res => {
  71. if (isContinue) {
  72. isContinue = false
  73. resolve(res)
  74. }
  75. },
  76. err => {
  77. if (isContinue) {
  78. isContinue = false
  79. reject(err)
  80. }
  81. }
  82. )
  83. })
  84. })
  85. }
  86. static all(promiseArr) {
  87. return new LPromise((resolve, reject) => {
  88. const resArr = []
  89. const length = promiseArr.length
  90. promiseArr.forEach(p => {
  91. p.then(
  92. res => {
  93. resArr.push(res)
  94. if (resArr.length === length) {
  95. resolve(resArr)
  96. }
  97. },
  98. err => reject(err)
  99. )
  100. })
  101. })
  102. }
  103. /* new content start */
  104. static allSettled(promiseArr) {
  105. return new LPromise(resolve => {
  106. const resArr = new Array(promiseArr.length)
  107. let num = 0
  108. promiseArr.forEach(p => {
  109. let obj = {}
  110. p.then(
  111. res => {
  112. obj.status = 'fulfilled'
  113. obj.value = res
  114. resArr[num] = obj
  115. num++
  116. if (num === resArr.length) resolve(resArr)
  117. },
  118. err => {
  119. obj.status = 'rejected'
  120. obj.reason = err
  121. resArr[num] = obj
  122. num++
  123. if (num === resArr.length) resolve(resArr)
  124. }
  125. )
  126. })
  127. })
  128. }
  129. /* new content end */
  130. }
  131. const p1 = new LPromise((resolve, reject) => setTimeout(() => resolve(1), 200))
  132. const p2 = new LPromise((resolve, reject) => setTimeout(() => reject(2), 1000))
  133. const p3 = new LPromise((resolve, reject) => setTimeout(() => reject(3), 3000))
  134. LPromise.allSettled([p1, p2, p3]).then(
  135. res => console.log('res', res),
  136. err => console.log('err', err)
  137. )

End

本文章实现的 Promise 不够完善,只是大概把实现原理带大家过一遍。Promise 的源码不是由 js 写的,所以我们只能尽可能使用 js 模仿。欢淫各位大佬补充更完善的版本。

交流学习~

微信:gdgzyw

github: www.github.com/layouwen