实现一个简易版的Promise

288 阅读5分钟

promise实现:

首先创建一个 MyPromise

 class MyPromise {
   constructor(executor) {
     this.state = 'pending' // 状态
     this.value = undefined // 保存 resolve 的值
     this.error = undefined // 保存 reject 的值

     // resolve 函数
     const resolve = value => {
       if (this.state === 'pending') {
         this.state = 'fullFilled'
         this.value = value
       }
     }

      // reject 函数
      const reject = error => {
        if (this.state === 'pending') {
          this.state = 'rejected'
          this.error = error
        }
      }

      // 执行通过 new MyPromise() 传进来函数
      executor(resolve, reject)
    }

    // then 方法
    then(onFullFilled, onRejected) {
      // 如果状态为 fullFilled,执行 resolve 回调
      if (this.state === 'fullFilled') {
        onFullFilled(this.value)
      }
      // 如果状态为 fullFilled,执行 reject 回调
      if (this.state === 'rejected') {
         onRejected(this.error)
      }
    }
  }
  // 测试基础功能
  new MyPromise((resolve, reject) => {
    if (Math.random() < 0.5) {
      resolve('fullFilled')
    } else {
      reject('rejected')
    }
  }).then(value => {
    console.log(value)
  }, error => {
    console.log(error)
  })

​ 以上代码,姑且实现最简单的 resolvereject,但是在Promise中,如果有语法错误,是会被捕获,然后触发reject的,所以还需要加上错误捕获

实现错误捕获

 try {
   // 执行通过 new MyPromise() 传进来函数
   executor(resolve, reject)
 } catch (e) {
   reject(e)
 }

// 测试捕获功能
new MyPromise((resolve, reject) => {
  // 故意打印一个未定义的值
  console.log(a)
}).then(value => {
  console.log(value)
}, error => {
  // 将会触发失败的回调函数
  console.log(error)
})

​ 这样就可以捕获错误并触发reject了,但是如果Promise使用异步触发resolve/reject时,以上代码就无法正常触发then中成功和失败的回调,所以需要利用发布订阅机制,事先保存好成功和失败的回调,然后在resolve/reject触发的时候,再去触发回调

实现异步触发 resolve/reject

...
this.onResolvedCallback = [] // 保存 resolve 回调
this.onRejectedCallback = [] // 保存 reject 回调
 
// resolve 函数
const resolve = value => {
  if (this.state === 'pending') {
    this.state = 'fullFilled'
    this.value = value
    this.onResolvedCallback.forEach(fn => fn())
  }
}

// reject 函数
const reject = error => {
  if (this.state === 'pending') {
     this.state = 'rejected'
     this.error = error
     this.onRejectedCallback.forEach(fn => fn())
  }
}
 // then 方法
 then(onFullFilled, onRejected) {
   ...
   // 如果状态为 pending,说明 resolve 或 reject 当前为异步执行,需保存其回调,延后执行
   if (this.state === 'pending') {
     this.onResolvedCallback.push(() => {
       onFullFilled(this.value)
     })
     
     this.onRejectedCallback.push(() => {
       onRejected(this.error)
     })
   }
 }

// 测试异步代码
new MyPromise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() < 0.5) {
      resolve(10)
    } else {
      reject(-10)
    }
  }, 1000)
}).then(value => {
  console.log(value)
}, error => {
  console.log(error)
})

​ 这样在异步触发resolve/reject的情况下,then中的成功回调和失败回调也能成功触发,接下来,要实现then的链式调用

实现 then 的链式调用

// then 方法
then(onFullFilled, onRejected) {
  let x

  return new MyPromise((resolve, reject) => {
    // 如果状态为 fullFilled,执行 resolve 回调
    if (this.state === 'fullFilled') {
      x = onFullFilled(this.value)
      resolve(x)
    }
    // 如果状态为 fullFilled,执行 reject 回调
    if (this.state === 'rejected') {
      x = onRejected(this.error)
      resolve(x)
    }
    // 如果状态为 pending,说明 resolve 或 reject 当前为异步执行,需保存其回调,延后执行
    if (this.state === 'pending') {
      this.onResolvedCallback.push(() => {
        x = onFullFilled(this.value)
        resolve(x)
      })
      this.onRejectedCallback.push(() => {
        x = onRejected(this.error)
        resolve(x)
      })
    }
  })
}

  // 测试链式调用
  const myPromise = new MyPromise((resolve, reject) => {
    if (Math.random() < 0.5) {
      resolve(10)
    } else {
      reject(-10)
    }
  })
  myPromise.then(value => {
    console.log('sucess:', value)
    return value + 2
  }, error => {
    console.log('fail:', error)
    return error - 2
  }).then(value => {
    console.log('sucess:', value)
    return value + 8
  }, error => {
    console.log('fail:', error)
    return error - 8
  }).then(value => {
    console.log('sucess:', value)
    return value + 10
  }, error => {
    console.log('fail:', error)
    return error - 10
  })

​ 这样就实现了then的链式调用,并且保证每个then中成功和失败的回调都返回一个promise对象,然后也要加上错误捕获机制

then 链式操作添加错误捕获

// then 方法
then(onFullFilled, onRejected) {
  let x

  return new MyPromise((resolve, reject) => {
    // 如果状态为 fullFilled,执行 resolve 回调
    if (this.state === 'fullFilled') {
      // 添加错误捕获机制
      try {
        x = onFullFilled(this.value)
        resolve(x)
      } catch (e) {
        reject(e)
      }
    }
    // 如果状态为 fullFilled,执行 reject 回调
    if (this.state === 'rejected') {
      // 添加错误捕获机制
      try {
        x = onRejected(this.error)
        resolve(x)
      } catch (e) {
        reject(e)
      }
    }
    // 如果状态为 pending,说明 resolve 或 reject 当前为异步执行,需保存其回调,延后执行
    if (this.state === 'pending') {
      this.onResolvedCallback.push(() => {
        // 添加错误捕获机制
        try {
          x = onFullFilled(this.value)
          resolve(x)
        } catch (e) {
          reject(e)
        }
      })
      this.onRejectedCallback.push(() => {
        // 添加错误捕获机制
        try {
          x = onRejected(this.error)
          resolve(x)
        } catch (e) {
          reject(e)
        }
      })
    }
  })
}

  // 测试链式调用中错误捕获功能
  const myPromise = new MyPromise((resolve, reject) => {
    if (Math.random() < 0.5) {
      resolve(10)
    } else {
      reject(-10)
    }
  })
  myPromise.then(value => {
    // 故意打印一个未定义的值
    console.log(a)
    return value + 2
  }, error => {
    // 故意打印一个未定义的值
    console.log(a)
    return error - 2
  }).then(value => {
    console.log('sucess:', value)
  }, error => {
    // 将会触发失败的回调函数
    console.log('fail:', error)
  })

​ 实现了这些之后,还存在一个问题,那就是如果我在then的成功或失败回调函数中又主动返回一个promise的时候,该如何处理这个promise和默认返回的promise的关系呢?

兼容返回值为 promise 对象的情况

// then 方法
then(onFullFilled, onRejected) {
    const promise =  new MyPromise((resolve, reject) => {
        let x

        // 如果状态为 fullFilled,执行 resolve 回调
        if (this.state === 'fullFilled') {
            try {
                x = onFullFilled(this.value)
                resolvePromise(x, resolve, reject)
            } catch (err) {
                reject(err)
            }
        }

        // 如果状态为 rejected,执行 reject 回调
        if (this.state === 'rejected') {
            try {
                x = onRejected(this.error)
                resolvePromise(x, resolve, reject)
            } catch (err) {
                reject(err)
            }
        }

        // 如果状态为 pending,说明 resolve 或 reject 当前为异步执行,需保存其回调,延后执行
        if (this.state === 'pending') {
            this.onResolvedCallback.push(() => {
                try {
                    x = onFullFilled(this.value)
                    resolvePromise(x, resolve, reject)
                } catch (err) {
                    reject(err)
                }
            })
            this.onRejectedCallback.push(() => {
                try {
                    x = onRejected(this.error)
                    resolvePromise(x, resolve, reject)
                } catch (err) {
                    reject(err)
                }
            })
        }
    })

    function resolvePromise(x, resolve, reject) {
        // 如果返回值是 promise 对象
        if (typeof x === 'object' && x !== null && typeof x.then === 'function') {
            x.then(value => {
                resolve(value)
            }, err => {
                reject(err)
            })
        } else {
            resolve(x)
        }
    }

    return promise
}

// 测试返回值为 Promise 对象的情况
const myPromise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() < 0.5) {
      resolve(10)
    } else {
      reject(-10)
    }
  })
})
myPromise.then(value => {
  console.log('sucess0:', value)
  // 主动返回一个 promise 对象
  return new MyPromise((resolve, reject) => {
    resolve(666)
  })
}, error => {
  console.log('fail0:', error)
  return new MyPromise((resolve, reject) => {
    resolve(222)
  })
})
.then(value => {
  console.log('sucess1:', value)
  return value
}, error => {
  console.log('fail1:', error)
  return error
})
.then(value => {
  console.log('sucess2:', value)
  return value
}, error => {
  console.log('fail2:', error)
  return error
})

​ 增加一个resolvePromise方法,用于判断返回对象的类型,如果是promise对象,则进一步处理后,再把处理好的值重新resolve。但是如果返回的promise对象中又嵌套promise的话,就需要用到递归来处理了

递归处理promise对象返回值

function resolvePromise(x, resolve, reject) {
    // 如果返回值是 promise 对象
    if (typeof x === 'object' && x !== null && typeof x.then === 'function') {
        console.log('aaa')
        x.then(value => {
            // 递归处理 promise 返回值
            resolvePromise(value, resolve, reject)
        }, err => {
            reject(err)
        })
    } else {
        console.log('bbb')
        resolve(x)
    }
}
// 测试返回值为 Promise 对象的情况
const myPromise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() < 0.5) {
      resolve(10)
    } else {
      reject(-10)
    }
  })
})
myPromise.then(value => {
  console.log('sucess0:', value)
  return new MyPromise((resolve, reject) => {
    // 嵌套多层 promise
    resolve(new MyPromise((resolve, reject) => {
      resolve(666)
    }))
  })
}, error => {
  console.log('fail0:', error)
  return new MyPromise((resolve, reject) => {
    resolve(222)
  })
})
.then(value => {
  console.log('sucess1:', value)
  return value
}, error => {
  console.log('fail1:', error)
  return error
})
.then(value => {
  console.log('sucess2:', value)
  return value
}, error => {
  console.log('fail2:', error)
  return error
})

完整的代码

class MyPromise {
    constructor(executor) {
      this.state = 'pending' // 状态
      this.value = undefined // 保存 resolve 的值
      this.error = undefined // 保存 reject 的值
      this.onResolvedCallback = [] // 保存 resolve 回调
      this.onRejectedCallback = [] // 保存 reject 回调

      // resolve 函数
      const resolve = value => {
        if (this.state === 'pending') {
          this.state = 'fullFilled'
          this.value = value
          this.onResolvedCallback.forEach(fn => fn())
        }
      }

      // reject 函数
      const reject = error => {
        if (this.state === 'pending') {
          this.state = 'rejected'
          this.error = error
          this.onRejectedCallback.forEach(fn => fn())
        }
      }

      try {
        // 执行通过 new MyPromise() 传进来函数
        executor(resolve, reject)
      } catch (e) {
        reject(e)
      }
    }

    // then 方法
    then(onFullFilled, onRejected) {
      const promise =  new MyPromise((resolve, reject) => {
        let x

        // 如果状态为 fullFilled,执行 resolve 回调
        if (this.state === 'fullFilled') {
          try {
            x = onFullFilled(this.value)
            resolvePromise(x, resolve, reject)
          } catch (err) {
            reject(err)
          }
        }

        // 如果状态为 rejected,执行 reject 回调
        if (this.state === 'rejected') {
          try {
            x = onRejected(this.error)
            resolvePromise(x, resolve, reject)
          } catch (err) {
            reject(err)
          }
        }

        // 如果状态为 pending,说明 resolve 或 reject 当前为异步执行,需保存其回调,延后执行
        if (this.state === 'pending') {
          this.onResolvedCallback.push(() => {
            try {
              x = onFullFilled(this.value)
              resolvePromise(x, resolve, reject)
            } catch (err) {
              reject(err)
            }
          })
          this.onRejectedCallback.push(() => {
            try {
              x = onRejected(this.error)
              resolvePromise(x, resolve, reject)
            } catch (err) {
              reject(err)
            }
          })
        }
      })

      function resolvePromise(x, resolve, reject) {
        // 如果返回值是 promise 对象
        if (typeof x === 'object' && x !== null && typeof x.then === 'function') {
          x.then(value => {
            resolvePromise(value, resolve, reject)
          }, err => {
            reject(err)
          })
        } else {
          resolve(x)
        }
      }

      return promise
    }
  }