手撸Promise

深度剖析Promise实现

1.1 resolve和reject

在这里插入图片描述

运行结果
在这里插入图片描述

这里说明了Promise的四个特点

  1. 执行了resolve,Promise状态会变成fulfilled;
  2. 执行了reject,Promise状态会变成rejected;
  3. Promise状态不可逆,第一次成功就永久为fulfilled,第一次失败就永远状态为rejected;
  4. Promise中有throw的话,就相当于执行了reject

1.1.1 实现resolve和reject

  1. Promise的初始状态是pending;
  2. 需要对resolve和reject绑定this:确保resolve和reject的this指向永远指向当前的MyPromise实例,防止随着函数执行环境的改变而改变
class MyPromise {
    constructor(executor) {
        this.initData() // 初始化
        this.initBind() // 初始化this指向
        executor(this.resolve, this.reject)
    }

    initData() {
        this.PromiseStatus = 'pending'
        this.PromiseResult = null
    }
    initBind() {
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
    }
    resolve(value) {
        this.PromiseStatus = 'fulfilled'
        this.PromiseResult = value
    }
    reject(reason) {
        this.PromiseStatus = 'rejected'
        this.PromiseResult = reason
    }
}

测试如下:
在这里插入图片描述

1.1.2 状态不可变

const test1 = new MyPromise((resolve, reject) => {
    resolve('success')
    reject('fail')
})
console.log(test1) // MyPromise { PromiseState: 'rejected', PromiseResult: 'fail' }

正确的应该是状态为fulfilled,但这里状态又变成了rejected。
Promise有三种状态:

  • pending:等待中,是初始状态;
  • fulfilled:成功状态;
  • rejected:失败状态;
    一旦状态从pending变为fulfilled或者rejected,那么此Promise实例的状态就不可以改变了。
    在这里插入图片描述
    这一步只需要:
   resolve(value) {
        // status是不可变的
        if (this.PromiseStatus !== 'pending') return
        this.PromiseStatus = 'fulfilled'
        this.PromiseResult = value
    }
    reject(reason) {
          // status是不可变的
        if (this.PromiseStatus!== 'pending') return
        this.PromiseStatus = 'rejected'
        this.PromiseResult = reason
    }

测试如下:

在这里插入图片描述

1.1.3 throw

Promise中有throw的话,就相当于执行了reject。这就要使用try catch了

+        try {
            // 执行传进来的函数
            executor(this.resolve, this.reject)
+        } catch (error) {
            // 捕捉到错误直接执行reject
+            this.reject(error)
+        }

完整代码如下
在这里插入图片描述
测试如下

在这里插入图片描述

1.2 then

平时业务中then的使用一般如下:

// 马上输出 ”success“
const p1 = new Promise((resolve, reject) => {
    resolve('success')
}).then(res => console.log(res), err => console.log(err))
// 1秒后输出 ”fail“
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('fail')
    }, 1000)
}).then(res => console.log(res), err => console.log(err))
// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
    resolve(100)
}).then(res => 2 * res, err => console.log(err))
  .then(res => console.log(res), err => console.log(err))

根据上述代码可以确定:

  1. then接收两个回调,一个是成功回调,一个是失败回调;
  2. 当Promise状态为fulfilled执行成功回调,为rejected执行失败回调;
  3. 如resolve或reject在定时器里,则定时器结束后再执行then;
  4. then支持链式调用,下一次then执行受上一次then返回值的影响;

1.2.1 实现then

then(onFulfilled, onRejected) {
        //参数校验,确保一定是函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
        onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
        if(this.PromiseStatus === 'fulfilled') {
            onFulfilled(this.PromiseResult)
        }
        else if(this.PromiseStatus === 'rejected') {
            onRejected(this.PromiseResult)
        }
    }

完整代码如下:
在这里插入图片描述

测试如下:
在这里插入图片描述

1.2.2 定时器

如何保证下述代码能够在1s后执行then的回调?

// 1秒后输出 ”fail“
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('fail')
    }, 1000)
}).then(res => console.log(res), err => console.log(err))

我们不能确保1秒后才执行then函数,但是我们可以保证1秒后再执行then里的回调
在这里插入图片描述
在这1秒时间内,我们可以先把then里的两个回调保存起来,然后等到1秒过后,执行了resolve或者reject,咱们再去判断状态,并且判断要去执行刚刚保存的两个回调中的哪一个回调。
那么问题来了,我们怎么知道当前1秒还没走完甚至还没开始走呢?其实很好判断,只要状态是pending,那就证明定时器还没跑完,因为如果定时器跑完的话,那状态肯定就不是pending,而是fulfilled或者rejected
那是用什么来保存这些回调呢?建议使用数组,因为一个promise实例可能会多次then,用数组就一个一个保存了

代码改造

在这里插入图片描述

const test2 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('success') // 2秒后输出 success
    }, 2000)
}).then(res => console.log(res), err => console.log(err))

1.2.3 链式调用

then支持链式调用,下一次then执行受上一次then返回值的影响

// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
  resolve(100)
}).then(res => 2 * res, err => console.log(err))
  .then(res => console.log(res), err => console.log(err))
// 链式调用 输出300
const p4 = new Promise((resolve, reject) => {
  resolve(100)
}).then(res => new Promise((resolve, reject) => resolve(3 * res)), err => console.log(err))
  .then(res => console.log(res), err => console.log(err))

根据上文,可以得到:

  1. then方法本身会返回一个新的Promise对象;
  2. 如果返回值是promise对象,返回值为成功,新promise就是成功;
  3. 如果返回值是promise对象,返回值为失败,新promise就是失败;
  4. 如果返回值非promise对象,新promise对象就是成功,值为此返回值;

then是Promise上的方法,那如何实现then完还能再then呢?
then执行后返回一个Promise对象就行了,就能保证then完还能继续执行then;

代码如下:

class MyPromise {
    constructor(executor) {
        this.initData() // 初始化
        this.initBind() // 初始化this指向
        try {
            executor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
    }

    initData() {
        this.PromiseStatus = 'pending'
        this.PromiseResult = null
        this.onFulfilledCallback = [] 
        this.onRejectedCallback = []
    }
    initBind() {
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
    }
    resolve(value) {
        if (this.PromiseStatus !== 'pending') return
        this.PromiseStatus = 'fulfilled'
        this.PromiseResult = value
        while(this.onFulfilledCallback.length) {
            this.onFulfilledCallback.shift()(this.PromiseResult)
        }
    }
    reject(reason) {
        if (this.PromiseStatus !== 'pending') return
        this.PromiseStatus = 'rejected'
        this.PromiseResult = reason
        while(this.onRejectedCallback) {
            this.onRejectedCallback.shift()(this.PromiseResult)
        }
    }
    then(onFulfilled, onRejected) {
        // 参数校验 
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
        onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}

        var resultPromise = new MyPromise((resolve,reject)=> {
            const resolvePromise = cb => {
                try {
                    const x = cb(this.PromiseResult)
                    if(x === resultPromise && x) {
                        // 不能返回自身
                        throw new Error('不能返回自身。。。')
                    }
                    if(x instanceof MyPromise) {
                         // 谁知道返回的promise是失败成功?只有then知道
                         x.then(resolve,reject)
                    }
                    else {
                        // 非Promise就直接是成功
                        resolve(x)
                    }
                } catch (error) {
                    reject(error)
                    throw new Error(error)
                }
            }
            if(this.PromiseStatus === 'fulfilled') {
                resolvePromise(onFulfilled)
            }
            else if(this.PromiseStatus === 'rejected') {
                resolvePromise(onRejected)
            }
            else if(this.PromiseStatus === 'pending') {
                // 保存回调
                this.onFulfilledCallback.push(resolvePromise.bind(this, onFulfilled))
                this.onRejectedCallback.push(resolvePromise.bind(this, onRejected))
            }
        })
        // 返回包装后的Promise
        return resultPromise

        
    }
}

测试如下:

在这里插入图片描述

1.2.4 执行顺序

这里需要了解,then方法是微任务

const p = new Promise((resolve, reject) => {
    resolve(1)
}).then(res => console.log(res), err => console.log(err))
console.log(2)
输出顺序是 2 1

这里为了实现类似的功能,使用setTimeout代替(setTimeout为宏任务,此处主要跟在全局上的console对比)

完整代码

class MyPromise {
  constructor(executor) {
    this.initData(); // 初始化
    this.initBind(); // 初始化this指向
    try {
      executor(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }

  initData() {
    this.PromiseStatus = "pending";
    this.PromiseResult = null;
    this.onFulfilledCallback = [];
    this.onRejectedCallback = [];
  }
  initBind() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }
  resolve(value) {
    if (this.PromiseStatus !== "pending") return;
    this.PromiseStatus = "fulfilled";
    this.PromiseResult = value;
    while (this.onFulfilledCallback.length) {
      this.onFulfilledCallback.shift()(this.PromiseResult);
    }
  }
  reject(reason) {
    if (this.PromiseStatus !== "pending") return;
    this.PromiseStatus = "rejected";
    this.PromiseResult = reason;
    while (this.onRejectedCallback) {
      this.onRejectedCallback.shift()(this.PromiseResult);
    }
  }
  then(onFulfilled, onRejected) {
    // 参数校验
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (val) => val;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };

    var resultPromise = new MyPromise((resolve, reject) => {
      const resolvePromise = (cb) => {
        setTimeout(() => {
          try {
            const x = cb(this.PromiseResult);
            if (x === resultPromise && x) {
              // 不能返回自身
              throw new Error("不能返回自身。。。");
            }
            if (x instanceof MyPromise) {
              // 谁知道返回的promise是失败成功?只有then知道
              x.then(resolve, reject);
            } else {
              // 非Promise就直接是成功
              resolve(x);
            }
          } catch (error) {
            reject(error);
            throw new Error(error);
          }
        });
      };
      if (this.PromiseStatus === "fulfilled") {
        resolvePromise(onFulfilled);
      } else if (this.PromiseStatus === "rejected") {
        resolvePromise(onRejected);
      } else if (this.PromiseStatus === "pending") {
        // 保存回调
        this.onFulfilledCallback.push(resolvePromise.bind(this, onFulfilled));
        this.onRejectedCallback.push(resolvePromise.bind(this, onRejected));
      }
    });
    // 返回包装后的Promise
    return resultPromise;
  }
}

const test4 = new MyPromise((resolve, reject) => {
  resolve(1);
}).then(
  (res) => console.log(res),
  (err) => console.log(err)
);
console.log(2);

测试如下:

在这里插入图片描述

Promise方法

1.3.1 all

  1. 接收一个Promise数组,数组中如有非Promise项,则此项当做成功;
  2. 如果所有Promise都成功,则返回成功结果数组;
  3. 如果有一个Promise失败,则返回这个失败结果;

在这里插入图片描述

1.3.2 race

  1. 接收一个Promise数组,数组中如有非Promise项,则此项当做成功;
  2. 哪个Promise最快得到结果,就返回那个结果,无论成功失败;

在这里插入图片描述

1.3.3 allSettled

  1. 接收一个Promise数组,数组中如有非Promise项,则此项当做成功;
  2. 把每一个Promise的结果,集合成数组后返回;

在这里插入图片描述

1.3.4 any

  1. 接收一个Promise数组,数组中如有非Promise项,则此项当做成功;
  2. 如果有一个Promise成功,则返回这个成功结果;
  3. 如果所有Promise都失败,则报错;

在这里插入图片描述

小结

本章节只是实现了简版的Promise,完整的Promise还涉及到Promise/A+的规范,感兴趣的小伙伴可以到官网上学习
官方地址

github地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bin_123ge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值