理解手动实现基础Promise

手动实现一个简单的 Promise 使得我们对 Promise 的深入理解,但是实现一个 Promise 会有哪些需求呢?

理解自定义 Promise 的需求

  • 一个构造函数,内部定义 Promise 的状态 pending/fulfilled/rejected 等相关数据。
  • 构造函数中参数执行器,执行器在实例化 Promise 的时候就开始执行。
  • then 方法,参数是两个函数,第一个是 成功 调用的方法,第二个是 失败 调用的方法。返回值是 的 Promise。
  • 状态转换。如果成功时,需要执行成功的回调,然后将状态 pending ->fulfilled。如果失败时,需要执行失败回调,然后将状态 pending->rejected 函数。
  • 异步实现。异步一般使用 setTimeout 和 setImmediate 或者其他的异步方案来实现即可。
  • 链式调用。then 种返回一个 Promise 即可。
  • 错误处理。链式调用的 catch 方法 或者 then 方法中的第二个函数。
  • 值(错误)传递。在状态转换的时候需要正确传递值和拒绝的原因。
  • 其他的方法。 Promise 还实现了很多其他的方法,更具需求自己实现。

构造函数

添加构造函数,并定义初始状态属性:

ts 复制代码
class MyPromise {
   constructor() {
        this.state = 'pending';
   }
}

添加 Promise 的执行

ts 复制代码
class MyPromise {
   constructor(executor) {
        this.state = 'pending';
   }
   
   try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
}

在内定义 executor 的参数决策成功和失败的函数

ts 复制代码
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.error = undefined;
    this.onFulfilled = [];
    this.onRejected = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilled.forEach((callback) => callback(this.value));
      }
    };

    const reject = (error) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.error = error;
        this.onRejected.forEach((callback) => callback(this.error));
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
}
  • 决策成功的函数 resolve 调用将 state 转变成 fulfilled, resolve 决策的值时保存在 value 种,然后将 onFulfilled 中保存的函数,全部重新调用一次。onFulfilled 时值得关注 onFulfilled 数组中。
  • 决策失败的函数 reject 调用将 state 转换成 rejected。将 错误保存起来,然后遍历 onRejected 数组将所有函数执行一次。

在 Promise 示例化之后, 执行器 executor 需要立即执行。

then 方法

then 的逻辑是返回 新的 Promise

ts 复制代码
then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        try {
          const result = onFulfilled(this.value);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      } else if (this.state === 'rejected') {
        try {
          const result = onRejected(this.error);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      } else {
        this.onFulfilled.push((value) => {
          try {
            const result = onFulfilled(value);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });

        this.onRejected.push((error) => {
          try {
            const result = onRejected(error);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });
      }
    });
}

测试用例

ts 复制代码
const p = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('success');
  }, 1000);
}
)

p.then((r) => {
  console.log(r)
}, (e) => {
  console.log(e)
})

const pe = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject('error');
  }, 1000);
}
)

pe.then((r) => {
  console.log(r)
}, (e) => {
  console.error("error", e)
})

完整实现

ts 复制代码
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.error = undefined;
    this.onFulfilled = [];
    this.onRejected = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilled.forEach((callback) => callback(this.value));
      }
    };

    const reject = (error) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.error = error;
        this.onRejected.forEach((callback) => callback(this.error));
      }
    };

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

  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        try {
          const result = onFulfilled(this.value);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      } else if (this.state === 'rejected') {
        try {
          const result = onRejected(this.error);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      } else {
        this.onFulfilled.push((value) => {
          try {
            const result = onFulfilled(value);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });

        this.onRejected.push((error) => {
          try {
            const result = onRejected(error);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });
      }
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }
}

小结

手动实现简单的 Promise, 关键在于理解 Promise 设计的业务模型,Promise 的实例化开始立即执行器中的函数 executor, 在内部定义 Promise 的状态,定义 Promise 所需要的执行器函数,已经在执行函数内部定义 resolve 和 reject 函数,最后还需要定义两个特殊的数组来处理进入 then 之后还是 pendding 状态处理函数,然后在角色之后遍历此数组接口。Promise 基本实现 then 方法以及 then 方法的链式调用,实现基本的 catch, catch 本质是一个特殊的 then 方法,只实现了 onRejected 部分。

相关推荐
香蕉可乐荷包蛋19 分钟前
浅入ES5、ES6(ES2015)、ES2023(ES14)版本对比,及使用建议---ES6就够用(个人觉得)
前端·javascript·es6
未来之窗软件服务1 小时前
资源管理器必要性———仙盟创梦IDE
前端·javascript·ide·仙盟创梦ide
my_styles1 小时前
docker-compose部署项目(springboot服务)以及基础环境(mysql、redis等)ruoyi-ry
spring boot·redis·后端·mysql·spring cloud·docker·容器
liuyang___2 小时前
第一次经历项目上线
前端·typescript
西哥写代码2 小时前
基于cornerstone3D的dicom影像浏览器 第十八章 自定义序列自动播放条
前端·javascript·vue
清风细雨_林木木2 小时前
Vue 中生成源码映射文件,配置 map
前端·javascript·vue.js
免檒2 小时前
go语言协程调度器 GPM 模型
开发语言·后端·golang
FungLeo3 小时前
node 后端和浏览器前端,有关 RSA 非对称加密的完整实践, 前后端匹配的代码演示
前端·非对称加密·rsa 加密·node 后端
不知道写什么的作者3 小时前
Flask快速入门和问答项目源码
后端·python·flask
不灭锦鲤3 小时前
xss-labs靶场第11-14关基础详解
前端·xss