用js实现promise

什么是Promise?

Promise代表了一个尚未完成但预期将来会完成的异步操作的结果。它有三种状态:

  1. Pending(等待中) :初始状态,既不是成功,也不是失败状态。
  2. Fulfilled(已成功) :意味着操作成功完成。
  3. Rejected(已失败) :意味着操作失败。

并且状态一旦改变就不能再更改了。

构造函数

Promise的构造函数接受一个执行器(executor)函数作为参数,该函数接收两个函数resolvereject作为参数。

例如我们平时使用的时候,实例化一个Promise对象

const p = new Promise((resolve, reject) => {
  let random = Math.floor(Math.random() * 10);
  if (random > 3) {
    resolve('sucess')
  } else {
    reject('error')
  }
})

结合Promise的三种状态,我们可以这样来设计构造函数

class myPromise {
  constructor(executor) {
    this.status = 'pending' // 初始状态 
    this.value = null // 存储成功值
    this.reason = null // 存储失败原因
    // 定义resolve函数
    const resolve = (val) => {
      if (this.state === 'pending') {
        this.status = 'fulfilled'
        this.value = val
      }
    }
    // 定义reject函数 
    const reject = (error) => {
      if (this.state === 'pending') {
        this.status = 'rejected';
        this.reason = error
      }
    }
    executor(resolve, reject)
  }
}

then和catch方法

Promise的then方法用于添加成功和失败的回调函数,并返回一个新的Promise对象以支持链式调用。

Promise 的 then 方法接受两个可选的参数:onFulfilled 和 onRejected。这两个参数分别是当 Promise 被解决(fulfilled)或拒绝(rejected)时调用的函数。

参数

  • onFulfilled (可选): 当 Promise 成功解决时调用的函数。该函数接收 Promise 解决时的值作为参数。
  • onRejected (可选): 当 Promise 被拒绝时调用的函数。该函数接收 Promise 拒绝的原因(reason)作为参数。

catch 方法是 Promise 链中用于错误处理的关键部分。它接收一个参数,即一个函数,这个函数会在 Promise 被拒绝时调用。这个函数接收一个参数,即拒绝的原因(reason)。

参数

  • onRejected (函数): 当 Promise 被拒绝时调用的函数。该函数接收拒绝的原因(reason)作为参数。

使用

p
  .then(res => {
    console.log(res);
  })
  .then(res => {
    console.log(res);
  })
  .catch(err => {
    console.log(err);
  })

设计then和catch方法

  then(onFulfilled) {
    if (this.status === 'fulfilled') {
      onFulfilled(this.value)
    }
  }
  catch(onRejected){
    if (this.status == 'rejected') {
      onRejected(this.reason)
    }
  }
}

但是这种方法不能实现链式调用,就是不能连着使用then方法。 但是如果我想实现出这个模式,我们应该在then方法下回一个对象,而这个对象正常来讲就是this

所以我们可以直接返回this吗,看下面这个情况。

p
  .then(res => {
    console.log(res);
    return new Promise((resolve, reject) => {
      resolve('1111')
    })
  })
  .then(res => {
    console.log(res);
  })
  .catch(err => {
    console.log(err);
  })

在then方法下如果返回了一个新的promise的话,我们就不能直接在then方法里面直接返回this了。

所以我们应该先判断then的回调函数是否返回了新的对象,如果没有才返回当前then的this对象。

  then(onFulfilled) {
    let res
    if (this.status === 'fulfilled') {
      res = onFulfilled(this.value)
    }
    return res || this
  }
  catch(onRejected){
    let rej
    if (this.status == 'rejected') {
      rej = onRejected(this.reason)
    }
    return rej || this
  }

解决异步问题

上面的代码,似乎看着没有什么问题了,但是如果我这么写的话:

let p = new Mypromise((resolve, reject) => {
  setTimeout(() => {
    reject('p resolve')
  }, 1000);
})

如果在Promise(假设为p)的then方法被调用时,定时器(即Promise所依赖的异步操作)还没有完成,那么Promise的状态将保持为pending,并且then中指定的回调函数不会立即执行。 为了解决这种情况,通常不会直接在Promise的创建过程中(即在new Promise(...)内部)就执行then方法中提供的回调函数,而是将这些回调函数保存起来,等到异步操作完成后再调用它们。

因此,我们需要用数组去存储成功和失败的回调函数

需要改造构造函数

  constructor(executor) {
    this.status = 'pending' // 初始状态 
    this.value = null // 存储成功值
    this.reason = null // 存储失败原因
    this.onFulfilledCallbacks = []; // 成功回调队列  
    this.onRejectedCallbacks = []; // 失败回调队列  
    // 定义resolve函数
    const resolve = (val) => {
      if (this.state === 'pending') {
        this.status = 'fulfilled'
        this.value = val
        this.onFulfilledCallbacks.forEach((fn)=>{
          fn(this.value)
        })
      }
    }
    // 定义reject函数 
    const reject = (error) => {
      if (this.state === 'pending') {
        this.status = 'rejected';
        this.reason = error
        this.onRejectedCallbacks.forEach((fn)=>{
          fn(this.reason)
        })
      }
    }
    executor(resolve, reject)
  }

同时修改then和catch方法

  then(onFulfilled) {
    if (this.status === 'pending'){
      this.onFulfilledCallbacks.push(onFulfilled)
    }
    let res
    if (this.status === 'fulfilled') {
      res = onFulfilled(this.value)
    }
    return res || this
  }
  catch(onRejected){
    if (this.status === 'pending'){
      this.onRejectedCallbacks.push(onRejected)
    }
    let rej
    if (this.status == 'rejected') {
      rej = onRejected(this.reason)
    }
    return rej || this
  }

完整代码

class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = null
    this.reason = null
    this.onResCallbacks = []
    this.onRejCallbacks = []
    const resolve = (val) => {
      if (this.state === 'pending') {
        this.state = 'fufilled'
        this.value = val
        this.onResCallbacks.forEach((fn) => {
          fn(this.value)
        })
      }
    }
    const reject = (err) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = err
        this.onRejCallbacks.forEach((fn) => {
          fn(this.reason)
        })
      }
    }
    executor(resolve, reject)
  }
  then(onFufilled) {
    if (this.state === 'pending') {
      this.onResCallbacks.push(onFufilled)
    }
    let res
    if (this.state === 'fufilled') {
      res = onFufilled(this.value)
    }
    return res || this
  }
  catch(onRejected) {
    if (this.state === 'pending') {
      this.onRejCallbacks.push(onRejected)
    }
    let rej
    if (this.state === 'rejected') {
      rej = onRejected(this.reason)
    }
    return rej || this
  }
}

const p = new myPromise((res,rej)=>{
  res(1)
}).then((data)=>{
  console.log(data);
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值