Promise自定义封装


1. 初始结构搭建

在这里插入图片描述


2.resolve与reject结构搭建

在这里插入图片描述


3. resolve与reject代码实现

注意一下resolvereject函数里如果直接使用this的话是指向window的,不是指向实例的
在这里插入图片描述


4. throw抛出异常改变状态

抛出异常会把promise对象状态变为失败,且失败值是抛出的错误
try-catch能处理throw抛出的异常,try-catch应该放在执行器函数执行的地方
在这里插入图片描述


5. Promise对象状态只能修改一次

promise对象的状态只能修改一次,只能从pending=>resolve或者pending=>reject
也就是说如下代码输出的应该是一个成功的promise对象
在这里插入图片描述
但是用我们自定义的promise,得到了错误的结果
在这里插入图片描述
很简单,在我们的resolvereject函数中都加入判断即可
在这里插入图片描述


6. then方法执行回调

这里能用this,因为调用then()方法的就是promise实例,所以this指向的就是promise实例

我们知道then()方法的两个参数的函数有两个形参都是函数,那这里肯定是需要两个实参的,onResolvedonRejected,在对应状态改变了的时候调用这两个函数,并把结果值传进去
在这里插入图片描述


7. 异步任务回调的执行

现在我们要将处理的同步任务换成异步任务
如下面代码:
在这里插入图片描述
控制台没有输出任何东西
为什么?
因为当调用then()方法的时候,resolve()还没有执行,就是说promise对象的状态还没改变
那我们的then()方法的这两个判断都进不去
在这里插入图片描述
显然我们这里还需要再多加一个判断,
if(this.PromiseState) === 'pending{}'
在这个判断里面写一些东西

我们还需要注意的是then()方法的onResolvedonRejected函数参数的执行时机,它们是在状态改变之后执行,我们的状态改变是在resolve()reject()函数里,所以我们也需要在这两个函数里调用一下onResolvedonRejected函数

现在是调不到的,它们是不同的函数。所以我们需要保存回调函数,并且保存在自己身上

新增一个属性callback
在这里插入图片描述
判断状态为pending时保存then()的这两个回调函数
在这里插入图片描述
当改变了状态,就调用这两个回调函数:
在这里插入图片描述


8. 指定多个回调的实现

我们前面说过如果为一个promise对象指定多个回调,这多个回调函数都是会执行的
那么如下代码应该会输出ok和value
在这里插入图片描述
但是我们的promise只输出了value,显然执行的是第二个then()方法的回调
也就是我们代码的这个位置,第一次进来的时候状态为pending保存了回调,第二次进来还是pending把第一次的回调覆盖掉了,那么这样会一次次覆盖掉之前的回调,事实上我们应该保存每一个回调
在这里插入图片描述
我们把callback属性改成数组,再把每一次回调push()进去:
在这里插入图片描述
在这里插入图片描述
打印一下我们的promise对象,callback中确实存好了这两次回调
在这里插入图片描述
那在状态改变之后调用回调函数的时候,应该遍历callback,执行里面的每一次回调
在这里插入图片描述
在这里插入图片描述


9. 同步任务下then方法返回结果

复习一下:
then()方法的返回结果是由它指定的回调函数的执行结果决定的

  • 这个回调函数如果返回一个非promise值then()返回的promise对象状态变为成功,成功值就是回调函数的返回值
  • 这个回调函数如果返回一个promise对象,这个promise对象就决定了then()返回的promise对象
  • 这个回调函数如果抛出异常,then()返回的promise对象状态变为失败,失败值就是回调函数的抛出错误

现在我们就要来实现让then()方法正确返回结果:
因为then()返回的promise状态和结果取决于它指定的回调函数执行结果,我们肯定要在这个执行结果res上进行一些判断

  • 如果回调函数返回非promise值then()返回的promise状态会变为成功,所以在这就要调用resolve(),而且成功值就是回调函数的返回值,也就是它的执行结果res,把res传进resolve()
  • 如果回调函数返回一个promise对象,意味着这个执行结果res是一个promise对象,它也可以调用then()方法。res如果成功,意味着then()返回的promise状态也是成功的,因为这个执行结果res返回的promise决定了then()返回的promise,而且状态成功它就一定会执行then()的第一个回调,所以在第一个回调里,就要调用resolve()then()返回的promise状态改为成功,而且then()返回的promise的成功结果就是执行结果res返回的promise的成功结果,所以调用resolve()的时候把value传进去

(这部分太难口头说清楚了,废话有点多见谅,我自己也有点懵逼🤦‍♀️)
在这里插入图片描述
测试一下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果回调函数如果抛出异常,then()也可以成功返回一个失败的promise对象
在这里插入图片描述
在这里插入图片描述

状态为rejected的时候也跟上面差不多一样的,补全就好了


10. 异步任务下then方法返回结果

下面我们将同步任务改成异步任务
在这里插入图片描述
我们的then()返回的结果显然是不正确的
在这里插入图片描述
分析一下我们的代码:
实例p调用我们的then()时,因为改成异步任务了,p的状态一定是pending。那么就会进入了我们的第三个判断,在这里面我们即没有调用resolve()也没有调用reject(),那我们的then()返回的promise状态肯定是pending
在这里插入图片描述
在这单纯调用onResolved()onRejected()这两回调已经不行了,得做点改进
下面这样,这个onResolved()函数在实例p状态改为成功时会执行,onRejected()实例p状态改为失败时会执行
在这里插入图片描述
因为我们上面定义的resolve()函数里把onResolved()都取出来调用了
在这里插入图片描述
现在要思考的是在onResolved()onRejected()中我们要做些什么
其实跟上面一样,同样也是分别在这两个函数里保存回调,根据回调来判断then()返回的promise的状态
在这里插入图片描述


11. catch() - 异常穿透和值传递

运行以下代码:
在这里插入图片描述
肯定会报错啦,毕竟我们都没有添加catch()方法,下面来实现它
直接调用已经写好的then()就行了
在这里插入图片描述
还要实现一个异常穿透功能:
在这里插入图片描述
需要在then()中加下面代码:
判断有没有传递onRejected参数,如果没有传,我们就帮它加一个定义,把错误抛出
then()还有一个值传递功能,就是两个参数都不传:
像以下代码:
我们的promise会报错
在这里插入图片描述
其实是因为第一个参数onResolved()我们既没有传递也没有定义,我们可以再为它定义一下onResolved()函数:
在这里插入图片描述


12. promise API - resolve()封装

在这里插入图片描述
resolve()方法返回一个promise,状态由传入的值决定,如果传入非promise值 => 状态成功,且成功值为传入值
如果传入promise对象 => 状态和结果由传入的promise对象决定

注意一下这个方法属于promise函数对象,不是属于promise实例对象在这里插入图片描述


13. promise API - reject()封装

在这里插入图片描述
reject()方法和resolve()方法不同在于:reject()方法返回的promise状态永远是失败的,失败值就是传入值
在这里插入图片描述


14. promise API - all()封装

在这里插入图片描述
all()接收一个由promise对象组成的数组,返回一个promise对象,状态由数组中的promise对象共同决定,所有的promise都成功,才算成功,否则失败

在这里插入图片描述


15. promise API - race()封装

在这里插入图片描述
race()也是接收一个由promise对象组成的数组,返回一个promise对象,状态由数组中第一个改变状态promise对象决定

谁先改变状态,谁就先执行回调,改变race()返回的promise的状态
在这里插入图片描述


16. then()回调的异步执行

then()指定的回调函数异步执行的,可以用下面代码测试内置的promise
在这里插入图片描述
可以看到then()指定的回调中的代码是最后执行的,这就是因为它是异步执行的,要等到同步执行代码执行完才会执行

在这里插入图片描述
用一下我们封装的promise
在这里插入图片描述
实现then()指定的回调异步执行
在这里插入图片描述
resolve()reject()中调用回调函数的地方也要套:
改变状态之后,不要立即调用回调
在这里插入图片描述


完整版:

function Promise(executor) {
  // 添加属性
  this.PromiseState = 'pending';
  this.PromiseResult = null;
  this.callback = [];
  // 保存实例对象的this值
  const self = this;
  // resolve函数
  function resolve(data) {
    // 判断状态
    if (self.PromiseState !== 'pending') {
      return
    }
    // 修改对象的状态 (promiseState)
    self.PromiseState = 'fulfilled';
    // 设置对象结果值 (promiseResult)
    self.PromiseResult = data;
    setTimeout(() => {
      // 调用成功的回调函数
      self.callback.forEach(item => {
        item.onResolved(data);
      })
    })
  }
  // reject函数
  function reject(data) {
    // 判断状态
    if (self.PromiseState !== 'pending') {
      return
    }
    // 修改对象的状态 (promiseState)
    self.PromiseState = 'rejected';
    // 设置对象结果值 (promiseResult)
    self.PromiseResult = data;

    // 调用失败的回调函数
    self.callback.forEach(item => {
      item.onRejected(data);
    })
  }
  try {
    // 同步调用执行器函数
    executor(resolve, reject);
  } catch (e) {
    // 修改 promise 对象的状态为失败,而且失败的结果值就是抛出的错误
    reject(e);
  }
}

// 添加then 方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this;
  // 判断回调函数参数
  if (typeof onRejected !== 'function') {
    onRejected = reason => {
      throw reason;
    }
  }
  if (typeof onResolved !== 'function') {
    onResolved = value => value;
  }
  return new Promise((resolve, reject) => {
    // 调用回调函数
    if (this.PromiseState === 'fulfilled') {
      setTimeout(() => {
        // 获取回调函数的执行结果
        let res = onResolved(this.PromiseResult);
        // 如果执行结果是promise类型的对象
        if (res instanceof Promise) {
          res.then(value => {
            resolve(value);
          }, reason => {
            reject(reason);
          })
        } else {
          // 返回结果的对象状态为成功,成功值就是回调函数返回的值
          resolve(res);
        }
      })
    }
    // 调用回调函数
    if (this.PromiseState === 'rejected') {
      setTimeout(() => {
        // 获取回调函数的执行结果
        let res = onRejected(this.PromiseResult);
        // 如果执行结果是promise类型的对象
        if (res instanceof Promise) {
          res.then(value => {
            resolve(value);
          }, reason => {
            reject(reason);
          })
        } else {
          // 返回结果的对象状态为成功,成功值就是回调函数返回的值
          resolve(res);
        }
      })
    }
    // 判断pending状态
    if (this.PromiseState === 'pending') {
      // 保存回调函数
      this.callback.push({
        // onResolved,
        onResolved() {
          try {
            // 保存成功的回调函数
            let res = onResolved(self.PromiseResult);
            if (res instanceof Promise) {
              res.then(value => {
                resolve(value);
              }, reason => {
                reject(reason);
              })
            } else {
              resolve(res);
            }
          } catch (e) {
            reject(e);
          }
        },
        // onRejected
        onRejected() {
          // 保存失败的回调函数
          let res = onRejected(self.PromiseResult);
          if (res instanceof Promise) {
            res.then(value => {
              resolve(value);
            }, reason => {
              reject(reason);
            })
          } else {
            resolve(res);
          }
        }
      })
    }
  })
}

// 添加catch方法
Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected);
}

// 添加resolve方法
Promise.resolve = function (param) {
  // 返回promise对象
  return new Promise((resolve, reject) => {
    // 由传递参数判断状态和结果值
    if (param instanceof Promise) {
      param.then(value => {
        resolve(value);
      }, reason => {
        reject(reason);
      })
    } else {
      // 状态设置为成功
      resolve(param);
    }
  })
}
// 添加reject方法
Promise.reject = function (param) {
  return new Promise((resolve, reject) => {
    reject(param);
  })
}

// 添加all方法
Promise.all = function (param) {
  return new Promise((resolve, reject) => {
    // 计数成功的promise个数
    let count = 0;
    // 新数组,保存结果
    let success = [];
    // 遍历传入的数组
    param.forEach(item => {
      item.then(value => {
        // 进入这个回调,说明成功,成功个数+1
        count++;
        // 成功值存进数组
        success.push(value);
        // 全部成功
        if (count === param.length) {
          resolve(success);
        }
      }, reason => {
        reject(reason);
      })
    })
  })
}
// 添加race方法
Promise.race = function (param) {
  return new Promise((resolve, reject) => {
    param.forEach(item => {
      item.then(value => {
        resolve(value);
      }, reason => {
        reject(reason);
      })
    })
  })
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Promise.all是一个函数,本质上也是一个Promise对象。它接收一个由多个Promise对象组成的数组作为参数,并返回一个新的Promise对象。当传入的所有Promise对象都变为Fulfilled状态时,返回的Promise对象才会变为Fulfilled状态,且以一个包含所有Promise对象结果的数组作为值。如果其中任何一个Promise对象变为Rejected状态,返回的Promise对象则会立即变为Rejected状态,并返回第一个Rejected Promise对象的错误信息。 在引用中的代码例子中,myPromiseall是一个自定义Promise.all函数实现。它接收一个可变数量的Promise对象作为参数,并返回一个新的Promise对象。在内部,通过遍历参数数组,对每一个Promise对象调用Promise.resolve方法,然后使用.then方法来处理每个Promise对象的结果。当所有Promise对象都成功解析时,将结果存入一个数组,并通过调用resolve方法来完成新Promise对象。如果任何一个Promise对象出现错误,则通过调用reject方法来捕获错误并返回新Promise对象的Rejected状态。 在引用中的代码例子中,getDataBind函数是一个通用的封装函数,接收一个处理函数和一个参数数组作为参数。它在内部使用map方法对参数数组中的每个元素调用处理函数,并返回一个新的数组。然后使用Promise.all方法将处理函数返回的Promise数组进行处理。 总而言之,Promise.all函数是用来处理多个Promise对象的工具函数,它能够方便地将多个异步操作并行执行,并在所有操作完成后返回一个包含所有结果的数组。<span class="em">1</span><span class="em">2</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值