我觉得实现 Promise,最难的部分是链式调用。下面是 Promise 链式调用的例子:

  1. (new Promise(resolve => {
  2. resolve(1)
  3. })).then(data => {
  4. console.log(data)
  5. return new Promise(
  6. resolve => setTimeout(() => resolve(2), 100)
  7. )
  8. }).then(data => {
  9. console.log(data)
  10. return Promise.resolve(3)
  11. }).then(data => console.log(data))

上面代码会依次输出: 1,2,3。链式调用就是一个个按顺序执行异步操作,把上一个 Promise 中 then 中的返回的数据,传递到到下一个 Promise 中。往下看前,大家可以试试看自己实现下 Promise 链式调用。

实现

1 支持非链式调用

我们先来实现个非链式调用的 MyPromise,满足下面的调用:

  1. // 情况1: 输出 1。
  2. (new MyPromise(resolve => {
  3. resolve(1)
  4. })).then(data => console.log(data));
  5. // 情况2: 输出 2。
  6. (new MyPromise(resolve => {
  7. setTimeout(() => resolve(2), 100)
  8. })).then(data => console.log(data))

实现代码如下:

  1. const PENDING = 'PENDING'
  2. const FULFILLED = 'FULFILLED'
  3. class MyPromise {
  4. constructor(fn) {
  5. this.status = PENDING
  6. this.data = null
  7. fn(this._resolve.bind(this))
  8. }
  9. _resolve(data) {
  10. if (this.status === PENDING) {
  11. this.status = FULFILLED
  12. this.data = data
  13. this.callback && this.callback(data)
  14. }
  15. }
  16. then(fulfilledCallback) {
  17. switch (this.status) {
  18. case PENDING: // 针对情况1
  19. this.callback = fulfilledCallback
  20. break;
  21. case FULFILLED: // 针对情况2
  22. fulfilledCallback(this.data)
  23. break;
  24. }
  25. }
  26. }

2 支持链式调用

满足下面的调用:

  1. // 依次输出:1,2,3
  2. (new MyPromise(resolve => {
  3. resolve(1)
  4. })).then((data) => {
  5. console.log(data)
  6. return new MyPromise(
  7. resolve => setTimeout(() => resolve(2), 100)
  8. )
  9. }).then((data) => {
  10. console.log(data)
  11. return new MyPromise(
  12. resolve => setTimeout(() => resolve(3), 100)
  13. )
  14. }).then((data) => {
  15. console.log(data)
  16. })

要支持链式调用,then 中返回的也应该是个 MyPromise 对象。并且返回的 MyPromise 对象要接上回调里的另一个 MyPromise 对象。只需改写 then 函数。代码实现如下:

  1. then(fulfilledCallback) {
  2. return new MyPromise((resolve, reject) => {
  3. const fulfilled = () => {
  4. const res = fulfilledCallback(this.data)
  5. return this.resolvePromise(res, resolve, reject)
  6. }
  7. switch (this.status) {
  8. case PENDING:
  9. this.callback = fulfilled
  10. break;
  11. case FULFILLED:
  12. fulfilled()
  13. break;
  14. }
  15. })
  16. }
  17. resolvePromise(fulfillRes, resolve, reject) {
  18. if(fulfillRes instanceof MyPromise) {
  19. // 把 resolve 的 data 往下传
  20. fulfillRes.then(resolve, reject)
  21. } else {
  22. resolve(this.data)
  23. }
  24. }

以上,就实现了 Promise 的链式调用。完整代码如下:

  1. const PENDING = 'PENDING'
  2. const FULFILLED = 'FULFILLED'
  3. class MyPromise {
  4. constructor(fn) {
  5. this.status = PENDING
  6. this.data = null
  7. fn(this._resolve.bind(this))
  8. }
  9. _resolve(data) {
  10. if (this.status === PENDING) {
  11. this.status = FULFILLED
  12. this.data = data
  13. this.callback && this.callback(data)
  14. }
  15. }
  16. then(fulfilledCallback) {
  17. return new MyPromise((resolve, reject) => {
  18. const fulfilled = () => {
  19. const res = fulfilledCallback(this.data)
  20. return this.resolvePromise(res, resolve, reject)
  21. }
  22. switch (this.status) {
  23. case PENDING:
  24. this.callback = fulfilled
  25. break;
  26. case FULFILLED:
  27. fulfilled()
  28. break;
  29. }
  30. })
  31. }
  32. // 实现链式的核心的代码
  33. resolvePromise(fulfillRes, resolve, reject) {
  34. if(fulfillRes instanceof MyPromise) {
  35. // 把 resolve 的 data 往下传
  36. fulfillRes.then(resolve, reject)
  37. } else {
  38. resolve(fulfillRes)
  39. }
  40. }
  41. }

推荐阅读

《从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节》: 详细讲了 Promise 的实现。