完整API

Promise是一个类

  • JS里类是一种特殊的函数
  • 类属性length(可忽略)其实就是几个参数
  • 类方法:all/allSettled/race/reject/resolve
  • 对象属性:then(重要)/finally/catch
  • 对象的内部属性:state=pending/fulfilled/rejected

37.手写Promise - 图1

API的规则

  • Promise/A+ 规格文档
  • 按照上面的文档写测试用例
  • 先失败后通过,直到文档中的情况都考虑清楚

    代码

    使用chai

  • $ yarn init -y

  • $ yarn global add ts-node mocha
  • $ yarn add chai mocha --dev
  • $ yarn add @types/chai @types/mocha --dev
  • 创建test/index.ts
  • $ mocha -r ts-node/register test/index.ts

将ts和ts-node安装到本地

  • $ yarn add --dev typescript ts-node
  • 写成脚本命令

package.json

  1. {
  2. ...
  3. "scripts": {
  4. "test": "mocha -r ts-node/register test/**/*.ts"
  5. },
  6. ...
  7. }

异步测试

src/promise.ts

  1. class Promise2 {
  2. succeed = null
  3. fail = null
  4. resolve() {
  5. setTimeout(() => { this.succeed() }, 0)
  6. }
  7. reject() {
  8. setTimeout(() => { this.fail() }, 0)
  9. }
  10. constructor(fn) {
  11. if (typeof fn !== 'function') {
  12. throw new Error("只接受函数")
  13. }
  14. fn(this.resolve.bind(this), this.reject.bind(this))
  15. }
  16. then(succeed, fail) {
  17. this.succeed = succeed
  18. this.fail = fail
  19. }
  20. }
  21. export default Promise2

test/index.ts

  1. import * as chai from 'chai'
  2. const assert = chai.assert
  3. import Promise from "../src/promise"
  4. describe('Promise', () => {
  5. it("Promise是一个类", () => {
  6. assert.isFunction(Promise)
  7. assert.isObject(Promise.prototype)
  8. })
  9. it("new Promise() 如果接受不是一个函数就报错", () => {
  10. assert.throw(() => {
  11. //@ts-ignore
  12. new Promise()
  13. })
  14. assert.throw(() => {
  15. //@ts-ignore
  16. new Promise(1)
  17. })
  18. assert.throw(() => {
  19. //@ts-ignore
  20. new Promise(false)
  21. })
  22. })
  23. it('new Promise(fn) 会生成一个对象,对象有then方法', () => {
  24. const promise = new Promise(() => { })
  25. assert.isFunction(promise.then)
  26. })
  27. it('new Promise(fn)中的fn立即执行', () => {
  28. let called = false
  29. const promise = new Promise(() => {
  30. called = true
  31. })
  32. //@ts-ignore
  33. assert(called === true)
  34. })
  35. it('new Promise(fn)中的fn执行的时候接受reject和resolve两个函数', () => {
  36. let called = false
  37. const promise = new Promise((resolve,reject) => {
  38. called = true
  39. assert.isFunction(resolve)
  40. assert.isFunction(reject)
  41. })
  42. //@ts-ignore
  43. assert(called === true)
  44. })
  45. it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
  46. let called=false;
  47. const promise = new Promise((resolve,reject) => {
  48. //该函数没有执行
  49. assert(called===false)
  50. resolve()
  51. //该函数执行了
  52. setTimeout(() => {
  53. assert(called===true)
  54. done()
  55. });
  56. })
  57. //@ts-ignore
  58. promise.then(()=>{
  59. called=true
  60. },()=>{})
  61. })
  62. });

$ yarn test
image.png

使用sinon测试函数

安装

  • $ yarn add --dev sinon sinon-chai
  • $ yarn add --dev @types/sinon @types/sinon-chai
    1. ...
    2. import * as sinon from 'sinon'
    3. import * as sinonChai from 'sinon-chai'
    4. chai.use(sinonChai)
    5. ...
    6. describe('Promise', () => {
    7. ...
    8. it('new Promise(fn)中的fn立即执行', () => {
    9. let fn = sinon.fake()
    10. new Promise(fn)
    11. assert(fn.called)
    12. })
    13. it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
    14. const success = sinon.fake()
    15. const promise = new Promise((resolve, reject) => {
    16. //该函数没有执行
    17. assert.isFalse(success.called)
    18. resolve()
    19. //该函数执行了
    20. setTimeout(() => {
    21. assert.isTrue(success.called)
    22. done()
    23. });
    24. })
    25. //@ts-ignore
    26. promise.then(success)
    27. })
    28. })

    根据Promise A+规范

/src/promise.ts

  1. class Promise2 {
  2. state = "pending"
  3. callBacks = []
  4. resolve(result) {
  5. if (this.state !== 'pending') return;
  6. this.state = 'fulfilled'
  7. setTimeout(() => {
  8. this.callBacks.forEach((handle) => {
  9. if (typeof handle[0] === 'function') {
  10. handle[0].call(undefined, result)
  11. }
  12. })
  13. }, 0)
  14. }
  15. reject(reason) {
  16. if (this.state !== 'pending') return;
  17. this.state = 'rejected'
  18. setTimeout(() => {
  19. this.callBacks.forEach((handle) => {
  20. if (typeof handle[1] === 'function') {
  21. handle[1].call(undefined, reason)
  22. }
  23. })
  24. }, 0)
  25. }
  26. constructor(fn) {
  27. if (typeof fn !== 'function') {
  28. throw new Error("只接受函数")
  29. }
  30. fn(this.resolve.bind(this), this.reject.bind(this))
  31. }
  32. then(succeed?, fail?) {
  33. const handle = []
  34. if (typeof succeed === 'function') {
  35. handle[0] = succeed
  36. }
  37. if (typeof fail === 'function') {
  38. handle[1] = fail
  39. }
  40. this.callBacks.push(handle)
  41. }
  42. }
  43. export default Promise2

/test/index.ts

  1. import * as chai from 'chai'
  2. import * as sinon from 'sinon'
  3. import * as sinonChai from 'sinon-chai'
  4. chai.use(sinonChai)
  5. const assert = chai.assert
  6. import Promise from "../src/promise"
  7. describe('Promise', () => {
  8. it("Promise是一个类", () => {
  9. assert.isFunction(Promise)
  10. assert.isObject(Promise.prototype)
  11. })
  12. it("new Promise() 如果接受不是一个函数就报错", () => {
  13. assert.throw(() => {
  14. //@ts-ignore
  15. new Promise()
  16. })
  17. assert.throw(() => {
  18. //@ts-ignore
  19. new Promise(1)
  20. })
  21. assert.throw(() => {
  22. //@ts-ignore
  23. new Promise(false)
  24. })
  25. })
  26. it('new Promise(fn) 会生成一个对象,对象有then方法', () => {
  27. const promise = new Promise(() => { })
  28. assert.isFunction(promise.then)
  29. })
  30. it('new Promise(fn)中的fn立即执行', () => {
  31. let fn = sinon.fake()
  32. new Promise(fn)
  33. assert(fn.called)
  34. })
  35. it('new Promise(fn)中的fn执行的时候接受reject和resolve两个函数', (done) => {
  36. new Promise((resolve, reject) => {
  37. assert.isFunction(resolve)
  38. assert.isFunction(reject)
  39. done()
  40. })
  41. })
  42. it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
  43. const success = sinon.fake()
  44. const promise = new Promise((resolve, reject) => {
  45. //该函数没有执行
  46. assert.isFalse(success.called)
  47. resolve()
  48. //该函数执行了
  49. setTimeout(() => {
  50. assert.isTrue(success.called)
  51. done()
  52. });
  53. })
  54. //@ts-ignore
  55. promise.then(success)
  56. })
  57. it('promise.then(null,fail)中的fail会在reject被调用的时候执行', (done) => {
  58. const fail = sinon.fake()
  59. const promise = new Promise((resolve, reject) => {
  60. //该函数没有执行
  61. assert.isFalse(fail.called)
  62. reject()
  63. //该函数执行了
  64. setTimeout(() => {
  65. assert.isTrue(fail.called)
  66. done()
  67. });
  68. })
  69. //@ts-ignore
  70. promise.then(null, fail)
  71. })
  72. it('2.2.1onFulfilled和onRejected都是可选的参数', () => {
  73. const promise = new Promise((resolve) => {
  74. resolve()
  75. })
  76. promise.then(false, null)
  77. assert(1 === 1)
  78. });
  79. it('2.2.2如果onFulfilled是函数', (done) => {
  80. const succeed = sinon.fake()
  81. const promise = new Promise((resolve) => {
  82. assert.isFalse(succeed.called)
  83. resolve(233)
  84. resolve(2333)
  85. setTimeout(() => {
  86. assert(promise.state === 'fulfilled')
  87. assert.isTrue(succeed.calledOnce)
  88. assert(succeed.calledWith(233))
  89. done()
  90. }, 0);
  91. })
  92. promise.then(succeed)
  93. });
  94. it('2.2.3如果onRejected是函数', (done) => {
  95. const fail = sinon.fake()
  96. const promise = new Promise((resolve, reject) => {
  97. assert.isFalse(fail.called)
  98. reject(233)
  99. reject(2333)
  100. setTimeout(() => {
  101. assert(promise.state === 'rejected')
  102. assert.isTrue(fail.calledOnce)
  103. assert(fail.calledWith(233))
  104. done()
  105. }, 0);
  106. })
  107. promise.then(null, fail)
  108. });
  109. it('2.2.4在我的代码完成之前不得调用then后面的成功函数', (done) => {
  110. const succeed = sinon.fake()
  111. const promise = new Promise((resolve) => {
  112. resolve()
  113. })
  114. promise.then(succeed)
  115. assert.isFalse(succeed.called)
  116. setTimeout(() => {
  117. assert.isTrue(succeed.called)
  118. done()
  119. }, 0);
  120. });
  121. it('2.2.4在我的代码完成之前不得调用then后面的失败函数', (done) => {
  122. const fn = sinon.fake()
  123. const promise = new Promise((resolve, reject) => {
  124. reject()
  125. })
  126. promise.then(null, fn)
  127. assert.isFalse(fn.called)
  128. setTimeout(() => {
  129. assert.isTrue(fn.called)
  130. done()
  131. }, 0);
  132. });
  133. it("2.2.5", (done) => {
  134. const promise = new Promise(resolve => {
  135. resolve()
  136. })
  137. promise.then(function () {
  138. "use strict"
  139. assert(this === undefined)
  140. done()
  141. })
  142. })
  143. it("2.2.6 then成功可以在同一个promise里被多次调用", (done) => {
  144. const promise = new Promise((resolve) => {
  145. resolve()
  146. })
  147. const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
  148. promise.then(callBacks[0])
  149. promise.then(callBacks[1])
  150. promise.then(callBacks[2])
  151. setTimeout(() => {
  152. assert(callBacks[0].called)
  153. assert(callBacks[1].calledAfter(callBacks[0]))
  154. assert(callBacks[2].calledAfter(callBacks[1]))
  155. done()
  156. }, 0);
  157. })
  158. it("2.2.6.2 then失败可以在同一个promise里被多次调用", (done) => {
  159. const promise = new Promise((resolve, reject) => {
  160. reject()
  161. })
  162. const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
  163. promise.then(null, callBacks[0])
  164. promise.then(null, callBacks[1])
  165. promise.then(null, callBacks[2])
  166. setTimeout(() => {
  167. assert(callBacks[0].called)
  168. assert(callBacks[1].calledAfter(callBacks[0]))
  169. assert(callBacks[2].calledAfter(callBacks[1]))
  170. done()
  171. }, 0);
  172. })
  173. });

$ yarn test
image.png

Promise解决程序

/src/promise.ts

  1. class Promise2 {
  2. state = "pending"
  3. callBacks = []
  4. resolve(result) {
  5. if (this.state !== 'pending') return;
  6. this.state = 'fulfilled'
  7. setTimeout(() => {
  8. this.callBacks.forEach((handle) => {
  9. if (typeof handle[0] === 'function') {
  10. const x = handle[0].call(undefined, result)
  11. handle[2].resolveWith(x)
  12. }
  13. })
  14. }, 0)
  15. }
  16. reject(reason) {
  17. if (this.state !== 'pending') return;
  18. this.state = 'rejected'
  19. setTimeout(() => {
  20. this.callBacks.forEach((handle) => {
  21. if (typeof handle[1] === 'function') {
  22. const x = handle[1].call(undefined, reason)
  23. handle[2].resolveWith(x)
  24. }
  25. })
  26. }, 0)
  27. }
  28. constructor(fn) {
  29. if (typeof fn !== 'function') {
  30. throw new Error("只接受函数")
  31. }
  32. fn(this.resolve.bind(this), this.reject.bind(this))
  33. }
  34. then(succeed?, fail?) {
  35. const handle = []
  36. if (typeof succeed === 'function') {
  37. handle[0] = succeed
  38. }
  39. if (typeof fail === 'function') {
  40. handle[1] = fail
  41. }
  42. handle[2] = new Promise2(() => { })
  43. this.callBacks.push(handle)
  44. return handle[2]
  45. }
  46. //2.2.7.1
  47. resolveWith(x) {
  48. //2.3.1 如果promise和x引用同一个对象,则用TypeError作为原因拒绝(reject)promise。
  49. if (this === x) {
  50. this.reject(new TypeError())
  51. } else if (x instanceof Promise2) {//2.3.2 如果x是一个promise,采用promise的状态3.4
  52. x.then((result) => {
  53. this.resolve(result)
  54. }, (reason) => {
  55. this.reject(reason)
  56. })
  57. }
  58. //2.3.3另外,如果x是个对象或者方法
  59. if (x instanceof Object) {
  60. let then
  61. try {
  62. then = x.then
  63. } catch (error) {
  64. this.reject(error)
  65. }
  66. if (then instanceof Function) {
  67. try {
  68. x.then((y) => {
  69. this.resolveWith(y)
  70. }, (r) => {
  71. this.reject(r)
  72. })
  73. } catch (error) {
  74. this.reject(error)
  75. }
  76. } else {
  77. this.resolve(x)
  78. }
  79. } else {
  80. this.resolve(x)
  81. }
  82. }
  83. }
  84. export default Promise2

/test/index.ts

  1. import * as chai from 'chai'
  2. import * as sinon from 'sinon'
  3. import * as sinonChai from 'sinon-chai'
  4. chai.use(sinonChai)
  5. const assert = chai.assert
  6. import Promise from "../src/promise"
  7. describe('Promise', () => {
  8. it("Promise是一个类", () => {
  9. assert.isFunction(Promise)
  10. assert.isObject(Promise.prototype)
  11. })
  12. it("new Promise() 如果接受不是一个函数就报错", () => {
  13. assert.throw(() => {
  14. //@ts-ignore
  15. new Promise()
  16. })
  17. assert.throw(() => {
  18. //@ts-ignore
  19. new Promise(1)
  20. })
  21. assert.throw(() => {
  22. //@ts-ignore
  23. new Promise(false)
  24. })
  25. })
  26. it('new Promise(fn) 会生成一个对象,对象有then方法', () => {
  27. const promise = new Promise(() => { })
  28. assert.isFunction(promise.then)
  29. })
  30. it('new Promise(fn)中的fn立即执行', () => {
  31. let fn = sinon.fake()
  32. new Promise(fn)
  33. assert(fn.called)
  34. })
  35. it('new Promise(fn)中的fn执行的时候接受reject和resolve两个函数', (done) => {
  36. new Promise((resolve, reject) => {
  37. assert.isFunction(resolve)
  38. assert.isFunction(reject)
  39. done()
  40. })
  41. })
  42. it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
  43. const success = sinon.fake()
  44. const promise = new Promise((resolve, reject) => {
  45. //该函数没有执行
  46. assert.isFalse(success.called)
  47. resolve()
  48. //该函数执行了
  49. setTimeout(() => {
  50. assert.isTrue(success.called)
  51. done()
  52. });
  53. })
  54. //@ts-ignore
  55. promise.then(success)
  56. })
  57. it('promise.then(null,fail)中的fail会在reject被调用的时候执行', (done) => {
  58. const fail = sinon.fake()
  59. const promise = new Promise((resolve, reject) => {
  60. //该函数没有执行
  61. assert.isFalse(fail.called)
  62. reject()
  63. //该函数执行了
  64. setTimeout(() => {
  65. assert.isTrue(fail.called)
  66. done()
  67. });
  68. })
  69. //@ts-ignore
  70. promise.then(null, fail)
  71. })
  72. it('2.2.1onFulfilled和onRejected都是可选的参数', () => {
  73. const promise = new Promise((resolve) => {
  74. resolve()
  75. })
  76. promise.then(false, null)
  77. assert(1 === 1)
  78. });
  79. it('2.2.2如果onFulfilled是函数', (done) => {
  80. const succeed = sinon.fake()
  81. const promise = new Promise((resolve) => {
  82. assert.isFalse(succeed.called)
  83. resolve(233)
  84. resolve(2333)
  85. setTimeout(() => {
  86. assert(promise.state === 'fulfilled')
  87. assert.isTrue(succeed.calledOnce)
  88. assert(succeed.calledWith(233))
  89. done()
  90. }, 0);
  91. })
  92. promise.then(succeed)
  93. });
  94. it('2.2.3如果onRejected是函数', (done) => {
  95. const fail = sinon.fake()
  96. const promise = new Promise((resolve, reject) => {
  97. assert.isFalse(fail.called)
  98. reject(233)
  99. reject(2333)
  100. setTimeout(() => {
  101. assert(promise.state === 'rejected')
  102. assert.isTrue(fail.calledOnce)
  103. assert(fail.calledWith(233))
  104. done()
  105. }, 0);
  106. })
  107. promise.then(null, fail)
  108. });
  109. it('2.2.4在我的代码完成之前不得调用then后面的成功函数', (done) => {
  110. const succeed = sinon.fake()
  111. const promise = new Promise((resolve) => {
  112. resolve()
  113. })
  114. promise.then(succeed)
  115. assert.isFalse(succeed.called)
  116. setTimeout(() => {
  117. assert.isTrue(succeed.called)
  118. done()
  119. }, 0);
  120. });
  121. it('2.2.4在我的代码完成之前不得调用then后面的失败函数', (done) => {
  122. const fn = sinon.fake()
  123. const promise = new Promise((resolve, reject) => {
  124. reject()
  125. })
  126. promise.then(null, fn)
  127. assert.isFalse(fn.called)
  128. setTimeout(() => {
  129. assert.isTrue(fn.called)
  130. done()
  131. }, 0);
  132. });
  133. it("2.2.5", (done) => {
  134. const promise = new Promise(resolve => {
  135. resolve()
  136. })
  137. promise.then(function () {
  138. "use strict"
  139. assert(this === undefined)
  140. done()
  141. })
  142. })
  143. it("2.2.6 then成功可以在同一个promise里被多次调用", (done) => {
  144. const promise = new Promise((resolve) => {
  145. resolve()
  146. })
  147. const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
  148. promise.then(callBacks[0])
  149. promise.then(callBacks[1])
  150. promise.then(callBacks[2])
  151. setTimeout(() => {
  152. assert(callBacks[0].called)
  153. assert(callBacks[1].calledAfter(callBacks[0]))
  154. assert(callBacks[2].calledAfter(callBacks[1]))
  155. done()
  156. }, 0);
  157. })
  158. it("2.2.6.2 then失败可以在同一个promise里被多次调用", (done) => {
  159. const promise = new Promise((resolve, reject) => {
  160. reject()
  161. })
  162. const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
  163. promise.then(null, callBacks[0])
  164. promise.then(null, callBacks[1])
  165. promise.then(null, callBacks[2])
  166. setTimeout(() => {
  167. assert(callBacks[0].called)
  168. assert(callBacks[1].calledAfter(callBacks[0]))
  169. assert(callBacks[2].calledAfter(callBacks[1]))
  170. done()
  171. }, 0);
  172. })
  173. it("2.2.7 then必须返回一个promise", () => {
  174. const promise = new Promise((resolve) => {
  175. resolve()
  176. })
  177. const promise2 = promise.then(() => { }, () => { })
  178. assert(promise2 instanceof Promise)
  179. })
  180. it("2.2.7.1 如果then(sucess,fail)中的success返回一个值x,运行[[Resolve]](promise2, x)", (done) => {
  181. const promise1 = new Promise((resolve) => {
  182. resolve()
  183. })
  184. promise1.then(() => "成功", () => { }).then(result => {
  185. assert.equal(result, "成功")
  186. done()
  187. })
  188. })
  189. it("2.2.7.1.2 x是一个promise实例", (done) => {
  190. const promise1 = new Promise((resolve) => {
  191. resolve()
  192. })
  193. const fn = sinon.fake()
  194. const promise2 = promise1.then(() => new Promise(resolve => resolve()))
  195. promise2.then(fn)
  196. setTimeout(() => {
  197. assert(fn.called)
  198. done()
  199. }, 1000);
  200. })
  201. });

宏任务与微任务

setTimeout改用process.nextTick
$ yarn add @types/node --dev
/tsconfig.json

  1. {
  2. "compilerOptions": {
  3. "types": [
  4. "node",
  5. "mocha"
  6. ]
  7. }
  8. }

/src/promise.ts

  1. class Promise2 {
  2. state = "pending"
  3. callBacks = []
  4. resolve(result) {
  5. if (this.state !== 'pending') return;
  6. this.state = 'fulfilled'
  7. process.nextTick(() => {
  8. this.callBacks.forEach((handle) => {
  9. if (typeof handle[0] === 'function') {
  10. let x
  11. try {
  12. x = handle[0].call(undefined, result)
  13. } catch (e) {
  14. return handle[2].reject(e)
  15. }
  16. handle[2].resolveWith(x)
  17. }
  18. })
  19. })
  20. }
  21. reject(reason) {
  22. if (this.state !== 'pending') return;
  23. this.state = 'rejected'
  24. process.nextTick(() => {
  25. this.callBacks.forEach((handle) => {
  26. if (typeof handle[1] === 'function') {
  27. let x
  28. try {
  29. x = handle[1].call(undefined, reason)
  30. } catch (e) {
  31. return handle[2].reject(e)
  32. }
  33. handle[2].resolveWith(x)
  34. }
  35. })
  36. })
  37. }
  38. constructor(fn) {
  39. if (typeof fn !== 'function') {
  40. throw new Error("只接受函数")
  41. }
  42. fn(this.resolve.bind(this), this.reject.bind(this))
  43. }
  44. then(succeed?, fail?) {
  45. const handle = []
  46. if (typeof succeed === 'function') {
  47. handle[0] = succeed
  48. }
  49. if (typeof fail === 'function') {
  50. handle[1] = fail
  51. }
  52. handle[2] = new Promise2(() => { })
  53. this.callBacks.push(handle)
  54. return handle[2]
  55. }
  56. //2.2.7.1
  57. resolveWith(x) {
  58. //2.3.1 如果promise和x引用同一个对象,则用TypeError作为原因拒绝(reject)promise。
  59. if (this === x) {
  60. this.reject(new TypeError())
  61. } else if (x instanceof Promise2) {//2.3.2 如果x是一个promise,采用promise的状态3.4
  62. x.then((result) => {
  63. this.resolve(result)
  64. }, (reason) => {
  65. this.reject(reason)
  66. })
  67. }
  68. //2.3.3另外,如果x是个对象或者方法
  69. if (x instanceof Object) {
  70. let then
  71. try {
  72. then = x.then
  73. } catch (error) {
  74. this.reject(error)
  75. }
  76. if (then instanceof Function) {
  77. try {
  78. x.then((y) => {
  79. this.resolveWith(y)
  80. }, (r) => {
  81. this.reject(r)
  82. })
  83. } catch (error) {
  84. this.reject(error)
  85. }
  86. } else {
  87. this.resolve(x)
  88. }
  89. } else {
  90. this.resolve(x)
  91. }
  92. }
  93. }
  94. export default Promise2

浏览器模拟nextTick

因为process.nextTick只存在node中,如何让浏览器也支持

MutationObserver

点击查看【codepen】

/src/promise.ts

  1. class Promise2 {
  2. state = "pending"
  3. callBacks = []
  4. resolve(result) {
  5. if (this.state !== 'pending') return;
  6. this.state = 'fulfilled'
  7. nextTick(() => {
  8. this.callBacks.forEach((handle) => {
  9. if (typeof handle[0] === 'function') {
  10. let x
  11. try {
  12. x = handle[0].call(undefined, result)
  13. } catch (e) {
  14. return handle[2].reject(e)
  15. }
  16. handle[2].resolveWith(x)
  17. }
  18. })
  19. })
  20. }
  21. reject(reason) {
  22. if (this.state !== 'pending') return;
  23. this.state = 'rejected'
  24. nextTick(() => {
  25. this.callBacks.forEach((handle) => {
  26. if (typeof handle[1] === 'function') {
  27. let x
  28. try {
  29. x = handle[1].call(undefined, reason)
  30. } catch (e) {
  31. return handle[2].reject(e)
  32. }
  33. handle[2].resolveWith(x)
  34. }
  35. })
  36. })
  37. }
  38. constructor(fn) {
  39. if (typeof fn !== 'function') {
  40. throw new Error("只接受函数")
  41. }
  42. fn(this.resolve.bind(this), this.reject.bind(this))
  43. }
  44. then(succeed?, fail?) {
  45. const handle = []
  46. if (typeof succeed === 'function') {
  47. handle[0] = succeed
  48. }
  49. if (typeof fail === 'function') {
  50. handle[1] = fail
  51. }
  52. handle[2] = new Promise2(() => { })
  53. this.callBacks.push(handle)
  54. return handle[2]
  55. }
  56. //2.2.7.1
  57. resolveWith(x) {
  58. //2.3.1 如果promise和x引用同一个对象,则用TypeError作为原因拒绝(reject)promise。
  59. if (this === x) {
  60. this.reject(new TypeError())
  61. } else if (x instanceof Promise2) {//2.3.2 如果x是一个promise,采用promise的状态3.4
  62. x.then((result) => {
  63. this.resolve(result)
  64. }, (reason) => {
  65. this.reject(reason)
  66. })
  67. }
  68. //2.3.3另外,如果x是个对象或者方法
  69. if (x instanceof Object) {
  70. let then
  71. try {
  72. then = x.then
  73. } catch (error) {
  74. this.reject(error)
  75. }
  76. if (then instanceof Function) {
  77. try {
  78. x.then((y) => {
  79. this.resolveWith(y)
  80. }, (r) => {
  81. this.reject(r)
  82. })
  83. } catch (error) {
  84. this.reject(error)
  85. }
  86. } else {
  87. this.resolve(x)
  88. }
  89. } else {
  90. this.resolve(x)
  91. }
  92. }
  93. }
  94. export default Promise2
  95. function nextTick(fn) {
  96. if (process !== undefined && typeof process.nextTick === 'function') {
  97. return process.nextTick(fn)
  98. }
  99. var counter = 1
  100. var observer = new MutationObserver(fn)
  101. var textNode = document.createTextNode(String(counter))
  102. observer.observe(textNode, {
  103. characterData: true
  104. })
  105. counter = (counter + 1) % 2
  106. textNode.data = String(counter)
  107. }

最终版本

优化代码
/src/promise.ts

  1. class Promise2 {
  2. state = "pending"
  3. callBacks = []
  4. private resolveOrReject(state, data, i) {
  5. if (this.state !== 'pending') return;
  6. this.state = state
  7. nextTick(() => {
  8. this.callBacks.forEach((handle) => {
  9. if (typeof handle[i] === 'function') {
  10. let x
  11. try {
  12. x = handle[i].call(undefined, data)
  13. } catch (e) {
  14. return handle[2].reject(e)
  15. }
  16. handle[2].resolveWith(x)
  17. }
  18. })
  19. })
  20. }
  21. resolve(result) {
  22. this.resolveOrReject('fulfilled', result, 0)
  23. }
  24. reject(reason) {
  25. this.resolveOrReject('rejected', reason, 1)
  26. }
  27. constructor(fn) {
  28. if (typeof fn !== 'function') {
  29. throw new Error("只接受函数")
  30. }
  31. fn(this.resolve.bind(this), this.reject.bind(this))
  32. }
  33. then(succeed?, fail?) {
  34. const handle = []
  35. if (typeof succeed === 'function') {
  36. handle[0] = succeed
  37. }
  38. if (typeof fail === 'function') {
  39. handle[1] = fail
  40. }
  41. handle[2] = new Promise2(() => { })
  42. this.callBacks.push(handle)
  43. return handle[2]
  44. }
  45. private resolveWithSelf() {
  46. this.reject(new TypeError())
  47. }
  48. private resolveWithPromise(x) {
  49. x.then((result) => {
  50. this.resolve(result)
  51. }, (reason) => {
  52. this.reject(reason)
  53. })
  54. }
  55. private getThen(x) {
  56. let then
  57. try {
  58. then = x.then
  59. } catch (error) {
  60. return this.reject(error)
  61. }
  62. return then
  63. }
  64. private resolveWithThenable(x) {
  65. try {
  66. x.then(y => {
  67. this.resolveWith(y)
  68. }, r => {
  69. this.reject(r)
  70. })
  71. } catch (error) {
  72. this.reject(error)
  73. }
  74. }
  75. private resolveWithObject(x) {
  76. let then = this.getThen(x)
  77. if (then instanceof Function) {
  78. this.resolveWithThenable(x)
  79. } else {
  80. this.resolve(x)
  81. }
  82. }
  83. resolveWith(x) {
  84. //2.3.1 如果promise和x引用同一个对象,则用TypeError作为原因拒绝(reject)promise。
  85. if (this === x) {
  86. this.resolveWithSelf()
  87. } else if (x instanceof Promise2) {
  88. this.resolveWithPromise(x)
  89. } else if (x instanceof Object) {
  90. this.resolveWithObject(x)
  91. } else {
  92. this.resolve(x)
  93. }
  94. }
  95. }
  96. export default Promise2
  97. function nextTick(fn) {
  98. if (process !== undefined && typeof process.nextTick === 'function') {
  99. return process.nextTick(fn)
  100. }
  101. var counter = 1
  102. var observer = new MutationObserver(fn)
  103. var textNode = document.createTextNode(String(counter))
  104. observer.observe(textNode, {
  105. characterData: true
  106. })
  107. counter = (counter + 1) % 2
  108. textNode.data = String(counter)
  109. }

最终测试代码

/test/index.ts

  1. import * as chai from 'chai'
  2. import * as sinon from 'sinon'
  3. import * as sinonChai from 'sinon-chai'
  4. chai.use(sinonChai)
  5. const assert = chai.assert
  6. import Promise from "../src/promise"
  7. describe('Promise', () => {
  8. it("Promise是一个类", () => {
  9. assert.isFunction(Promise)
  10. assert.isObject(Promise.prototype)
  11. })
  12. it("new Promise() 如果接受不是一个函数就报错", () => {
  13. assert.throw(() => {
  14. //@ts-ignore
  15. new Promise()
  16. })
  17. assert.throw(() => {
  18. //@ts-ignore
  19. new Promise(1)
  20. })
  21. assert.throw(() => {
  22. //@ts-ignore
  23. new Promise(false)
  24. })
  25. })
  26. it('new Promise(fn) 会生成一个对象,对象有then方法', () => {
  27. const promise = new Promise(() => { })
  28. assert.isFunction(promise.then)
  29. })
  30. it('new Promise(fn)中的fn立即执行', () => {
  31. let fn = sinon.fake()
  32. new Promise(fn)
  33. assert(fn.called)
  34. })
  35. it('new Promise(fn)中的fn执行的时候接受reject和resolve两个函数', (done) => {
  36. new Promise((resolve, reject) => {
  37. assert.isFunction(resolve)
  38. assert.isFunction(reject)
  39. done()
  40. })
  41. })
  42. it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
  43. const success = sinon.fake()
  44. const promise = new Promise((resolve, reject) => {
  45. //该函数没有执行
  46. assert.isFalse(success.called)
  47. resolve()
  48. //该函数执行了
  49. setTimeout(() => {
  50. assert.isTrue(success.called)
  51. done()
  52. });
  53. })
  54. //@ts-ignore
  55. promise.then(success)
  56. })
  57. it('promise.then(null,fail)中的fail会在reject被调用的时候执行', (done) => {
  58. const fail = sinon.fake()
  59. const promise = new Promise((resolve, reject) => {
  60. //该函数没有执行
  61. assert.isFalse(fail.called)
  62. reject()
  63. //该函数执行了
  64. setTimeout(() => {
  65. assert.isTrue(fail.called)
  66. done()
  67. });
  68. })
  69. //@ts-ignore
  70. promise.then(null, fail)
  71. })
  72. it('2.2.1onFulfilled和onRejected都是可选的参数', () => {
  73. const promise = new Promise((resolve) => {
  74. resolve()
  75. })
  76. promise.then(false, null)
  77. assert(1 === 1)
  78. });
  79. it('2.2.2如果onFulfilled是函数', (done) => {
  80. const succeed = sinon.fake()
  81. const promise = new Promise((resolve) => {
  82. assert.isFalse(succeed.called)
  83. resolve(233)
  84. resolve(2333)
  85. setTimeout(() => {
  86. assert(promise.state === 'fulfilled')
  87. assert.isTrue(succeed.calledOnce)
  88. assert(succeed.calledWith(233))
  89. done()
  90. }, 0);
  91. })
  92. promise.then(succeed)
  93. });
  94. it('2.2.3如果onRejected是函数', (done) => {
  95. const fail = sinon.fake()
  96. const promise = new Promise((resolve, reject) => {
  97. assert.isFalse(fail.called)
  98. reject(233)
  99. reject(2333)
  100. setTimeout(() => {
  101. assert(promise.state === 'rejected')
  102. assert.isTrue(fail.calledOnce)
  103. assert(fail.calledWith(233))
  104. done()
  105. }, 0);
  106. })
  107. promise.then(null, fail)
  108. });
  109. it('2.2.4在我的代码完成之前不得调用then后面的成功函数', (done) => {
  110. const succeed = sinon.fake()
  111. const promise = new Promise((resolve) => {
  112. resolve()
  113. })
  114. promise.then(succeed)
  115. assert.isFalse(succeed.called)
  116. setTimeout(() => {
  117. assert.isTrue(succeed.called)
  118. done()
  119. }, 0);
  120. });
  121. it('2.2.4在我的代码完成之前不得调用then后面的失败函数', (done) => {
  122. const fn = sinon.fake()
  123. const promise = new Promise((resolve, reject) => {
  124. reject()
  125. })
  126. promise.then(null, fn)
  127. assert.isFalse(fn.called)
  128. setTimeout(() => {
  129. assert.isTrue(fn.called)
  130. done()
  131. }, 0);
  132. });
  133. it("2.2.5", (done) => {
  134. const promise = new Promise(resolve => {
  135. resolve()
  136. })
  137. promise.then(function () {
  138. "use strict"
  139. assert(this === undefined)
  140. done()
  141. })
  142. })
  143. it("2.2.6 then成功可以在同一个promise里被多次调用", (done) => {
  144. const promise = new Promise((resolve) => {
  145. resolve()
  146. })
  147. const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
  148. promise.then(callBacks[0])
  149. promise.then(callBacks[1])
  150. promise.then(callBacks[2])
  151. setTimeout(() => {
  152. assert(callBacks[0].called)
  153. assert(callBacks[1].calledAfter(callBacks[0]))
  154. assert(callBacks[2].calledAfter(callBacks[1]))
  155. done()
  156. }, 0);
  157. })
  158. it("2.2.6.2 then失败可以在同一个promise里被多次调用", (done) => {
  159. const promise = new Promise((resolve, reject) => {
  160. reject()
  161. })
  162. const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
  163. promise.then(null, callBacks[0])
  164. promise.then(null, callBacks[1])
  165. promise.then(null, callBacks[2])
  166. setTimeout(() => {
  167. assert(callBacks[0].called)
  168. assert(callBacks[1].calledAfter(callBacks[0]))
  169. assert(callBacks[2].calledAfter(callBacks[1]))
  170. done()
  171. }, 0);
  172. })
  173. it("2.2.7 then必须返回一个promise", () => {
  174. const promise = new Promise((resolve) => {
  175. resolve()
  176. })
  177. const promise2 = promise.then(() => { }, () => { })
  178. assert(promise2 instanceof Promise)
  179. })
  180. it("2.2.7.1 如果then(sucess,fail)中的success返回一个值x,运行[[Resolve]](promise2, x)", (done) => {
  181. const promise1 = new Promise((resolve) => {
  182. resolve()
  183. })
  184. promise1.then(() => "成功", () => { }).then(result => {
  185. assert.equal(result, "成功")
  186. done()
  187. })
  188. })
  189. it("2.2.7.1.2 success的返回值是一个promise实例", (done) => {
  190. const promise1 = new Promise((resolve) => {
  191. resolve()
  192. })
  193. const fn = sinon.fake()
  194. const promise2 = promise1.then(() => new Promise(resolve => resolve()))
  195. promise2.then(fn)
  196. setTimeout(() => {
  197. assert(fn.called)
  198. done()
  199. }, 0);
  200. })
  201. it("2.2.7.1.2 success的返回值是一个promise实例,且失败了", (done) => {
  202. const promise1 = new Promise((resolve) => {
  203. resolve()
  204. })
  205. const fn = sinon.fake()
  206. const promise2 = promise1.then(() => new Promise((resolve, reject) => reject()))
  207. promise2.then(null, fn)
  208. setTimeout(() => {
  209. assert(fn.called)
  210. done()
  211. }, 0);
  212. })
  213. it("2.2.7.1.2 fail的返回值是一个promise实例", (done) => {
  214. const promise1 = new Promise((resolve, reject) => {
  215. reject()
  216. })
  217. const fn = sinon.fake()
  218. const promise2 = promise1.then(null, () => new Promise(resolve => resolve()))
  219. promise2.then(fn)
  220. setTimeout(() => {
  221. assert(fn.called)
  222. done()
  223. }, 0);
  224. })
  225. it("2.2.7.1.2 fail的返回值是一个promise实例且失败", (done) => {
  226. const promise1 = new Promise((resolve, reject) => {
  227. reject()
  228. })
  229. const fn = sinon.fake()
  230. const promise2 = promise1.then(null, () => new Promise((resolve, reject) => reject()))
  231. promise2.then(null, fn)
  232. setTimeout(() => {
  233. assert(fn.called)
  234. done()
  235. }, 0);
  236. })
  237. it("2.2.7.2 如果success抛出一个异常e,promise2 必须被拒绝(rejected)并把e当作原因",
  238. (done) => {
  239. const promise1 = new Promise((resolve, reject) => {
  240. resolve()
  241. })
  242. const fn = sinon.fake()
  243. const error = new Error()
  244. const promise2 = promise1.then(() => {
  245. throw error
  246. })
  247. promise2.then(null, fn)
  248. setTimeout(() => {
  249. assert(fn.called)
  250. assert(fn.calledWith(error))
  251. done()
  252. }, 0);
  253. }
  254. )
  255. it("2.2.7.2 如果fail抛出一个异常e,promise2 必须被拒绝(rejected)并把e当作原因",
  256. (done) => {
  257. const promise1 = new Promise((resolve, reject) => {
  258. reject()
  259. })
  260. const fn = sinon.fake()
  261. const error = new Error()
  262. const promise2 = promise1.then(null,() => {
  263. throw error
  264. })
  265. promise2.then(null, fn)
  266. setTimeout(() => {
  267. assert(fn.called)
  268. assert(fn.calledWith(error))
  269. done()
  270. }, 0);
  271. }
  272. )
  273. });

image.png