真丶深入理解JavaScript异步编程(最终章):手撸 Promise

本文深入探讨JavaScript异步编程,通过手写简易版Promise,逐步实现then的链式操作、状态穿透及处理返回Promise对象。详细解析MyPromise的核心方法,包括静态方法如resolve、reject、all和race。旨在帮助读者掌握Promise原理和异步运行机制。
摘要由CSDN通过智能技术生成

原文地址: https://www.jeremyjone.com/773/ ,转载请注明


写在前面

已经写了3篇前置内容了,主要是理解JS中的异步编程,异步的实现、以及异步的原理。今天内容较长,从最简单、最基本的内容入手,一点一点手撸一个简易的 Promise,巩固之前理解的异步原理,这才是我的目标。

手写 Promise

了解 Promise,从手动重写一个简易版的开始。

最简易的 Promise

最基本的 Promise 的样子是这样的:

new Promise((resolve, reject) => {
   });

那么照猫画虎写一个:

class MyPromise {
   
  constructor(executor) {
   
    this.status = "pending";
    this.value = null;

    try {
   
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
   
      this.reject(error);
    }
  }

  resolve(val) {
   
    if (this.status === "pending") {
   
      this.status = "fulfilled";
      this.value = val;
    }
  }

  reject(err) {
   
    if (this.status === "pending") {
   
      this.status = "rejected";
      this.value = err;
    }
  }
}

这样就得到了一个最基本的样子,来试一下:

let p1 = new MyPromise((resolve, reject) => {
   }); // 此时为 pending 状态

let p2 = new MyPromise((resolve, reject) => {
   
  resolve();
}); // 此时为 fulfilled 状态

let p3 = new MyPromise((resolve, reject) => {
   
  reject();
}); // 此时为 rejected 状态

好像没什么毛病了。接下来实现 then 的链式操作。

then 的实现

前文已经提到过,它应该也是一个方法,所以我们继续在 MyPromise 类中添加一个 then 方法:

// 继续添加代码,已有代码不再重复
class MyPromise {
   
  constructor(executor) {
   
    // 添加两个回调接收,用于 then 的异步回调
    this.cbFulfilled = null;
    this.cbRejected = null;
  }

  then(resolve, reject) {
   
    // 先判断两个参数是否为函数,如果不是或者没有,给一个默认值
    if (typeof resolve !== "function") {
   
      resolve = () => {
   };
    }

    if (typeof reject !== "function") {
   
      reject = () => {
   };
    }

    // 初始状态,异步情况下会是这个状态
    if (this.status === "pending") {
   
      this.cbFulfilled = resolve;
      this.cbRjected = reject;
    }

    // 成功状态
    if (this.status === "fulfilled") {
   
      setTimeout(() => {
   
        try {
   
          resolve(this.value);
        } catch (error) {
   
          reject(error);
        }
      });
    }

    // 失败
    if (this.status === "rejected") {
   
      setTimeout(() => {
   
        try {
   
          reject(this.value);
        } catch (error) {
   
          reject(error);
        }
      });
    }
  }

  // 修改之前的代码
  resolve(val) {
   
    if (this.status === "pending") {
   
      this.status = "fulfilled";
      this.value = val;

      // 添加回调
      setTimeout(() => {
   
        this.cbFulfilled && this.cbFulfilled("timeout " + this.value);
      });
    }
  }

  reject(err) {
   
    if (this.status === "pending") {
   
      this.status = "rejected";
      this.value = err;

      // 添加回调
      setTimeout(() => {
   
        this.cbRejected && this.cbRejected("timeout " + this.value);
      });
    }
  }
}

这里我们通过使用 setTimeout 来对执行顺序加以控制,使回调成为一个异步调用。测试一下:

let p1 = new MyPromise((resolve, reject) => {
   
  console.log(1);
  setTimeout(() => {
   
    resolve("jeremyjone");
    console.log(4);
  });
  console.log(2);
}).then(val => console.log(val));

console.log(3);

它的打印顺序:

1
2
3
4
jeremyjone

现在看上去已经和原生的效果差不多了。下一步我们让它成为链式的。

then 的链式实现

要实现链式操作,首先要明确:

  • 它本身返回一个 Promise
  • 它接收的状态并不会影响它新返回 Promise 的状态

既然是要一个 Promise,那么我们首先将 then 里面的方法包装在一个 Promise 中。然后稍微修改一下逻辑就可以实现链式操作了。

class MyPromise {
   
  // ... 其他代码省略

  then(resolve, reject) {
   
    // 先判断两个参数是否为函数,如果不是或者没有,给一个默认值
    if (typeof resolve !== "function") {
   
      reso
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值