手写promise

promise有一个then方法

  • 1、构造函数
  • 2、then方法
js 复制代码
promise A+规范,有then方法就可以;所以难点是then方法
new Promise((resolve, reject) => {})
观察Promise的用法,构造函数会传入一个函数,执行器executor
resolve和reject两个函数用来改变状态,pending -》 fullfiled 或 pending-〉rejected

1 构造函数

kotlin 复制代码
// 用常量定义字符串,利于维护
const PENDING = 'pending';
const FULLFIED = 'fullfied';
const REJECTED = 'rejected';
class MyPromise {
  #status = PENDING; // 变量前加#,表示私有属性
  #result = undefined;
  #handlers = [];
  constructor(executor) {
    const resolve = (data) => {
      this.#changeState(FULLFIED, data);
    };

    const reject = (reason) => {
      this.#changeState(REJECTED, reason);
    };

    // try catch 只能捕获同步错误
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  #changeState(status, data) {
    if (this.#status !== PENDING) {
      return;
    }
    this.#status = status;
    this.#result = data;
    console.log(this.#status, this.#result);
    #run();
  }
 }

2 接下来考虑then

graph TD then --> handler then --> #run #changeState --> #run #run --> handler
arduino 复制代码
// 传入的回调什么时候运行:将回调收集起来,用户可能会调用多次then,所以使用数组收集
// then返回的promise
// 挂起的状态,有异步代码情况,所以需要状态改变时执行回调函数
// 将回调函数都收集起来

// 传入的回调不是函数,穿透
// 目前状态是成功,传入的回调不是函数
// 目前状态是失败,传入的回调不是函数

// 运行回调函数,返回回调函数运行结果【&执行回调】
js 复制代码
#runOne(callback, resolve, reject) {
    if (typeof callback !== 'function') {
      const settled = this.#status === FULLFIED ? resolve : reject;
      settled(this.#result);
      return;
    }

    try {
      const data = callback(this.#result);
      resolve(data);【&执行回调】
    } catch (err) {
      reject(err);
    }
}

// 在changeState状态改变函数中也要调用run方法
#run() {
    if (this.#status === PENDING) return;
    while (this.#handlers.length) {
      const { onFullfilled, onRejected, resolve, reject } =
        this.#handlers.shift();

      if (this.#status === FULLFIED) {
        this.#runOne(onFullfilled, resolve, reject);
      } else {
        this.#runOne(onRejected, resolve, reject);
      }
      // 提取函数runOne
      // if (this.#status === FULLFIED) {
      //   if (typeof onFullfilled === 'function') {
      //     try {
      //       const data = onFullfilled(this.#result);
      //       resolve(data);
      //     } catch (err) {
      //       reject(err);
      //     }
      //   } else {
      //     resolve(this.#result);
      //   }
      // } else {
      //   if (typeof onRejected === 'function') {
      //     try {
      //       const data = onRejected(this.#result);
      //       resolve(data);
      //     } catch (err) {
      //       reject(err);
      //     }
      //     onRejected(this.#result);
      //   } else {
      //     // 目前状态时成功,传入的回调不是函数
      //     // 目前状态时失败,传入的回调不是函数
      //     // 穿透,resolve或者reject
      //     // 穿透
      //     reject(this.#result);
      //   }
      // }
    }
  }
  // 传入的回调什么时候运行:将回调收集起来,用户可能会调用多次then,所以使用数组收集
  // then返回的promise
  then(onFullfilled, onRejected) {
    return new Promise((resolve, reject) => {
      // 挂起的状态,有异步代码情况,所以需要状态改变时执行回调函数
      // 将回调函数都收集起来
      this.#handlers.push({
        onFullfilled,
        onRejected,
        resolve,
        reject,
      });

      this.#run();
    });
  }
js 复制代码
const p = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject(234);
  }, 1000);

  // throw 123;
});
console.log(p);

p.then(
  (res) => {
    console.log('成功1', res);
  },
  (err) => {
    console.log('失败1', err);
  }
);
p.then(
  // (res) => {
  //   console.log('成功2', res);
  // },
  null,
  (err) => {
    console.log('失败2', err);
  }
);
p.then(
  (res) => {
    console.log('成功3', res);
  },
  (err) => {
    console.log('失败3', err);
    return 222;
  }
).then((res) => {
  console.log(res);
});

// 原生promise也无法捕获异步错误
// const p1 = new Promise((resolve, reject) => {
//   setTimeout(() => {
//     throw 123;
//   }, 0);
// });
相关推荐
一心只读圣贤书几秒前
AI 驱动前端测试实战:从需求文档到 Playwright 自动化用例
前端·人工智能
拖孩7 分钟前
用 AI 重解千年观音灵签,做了一个微信小程序,每天摇一摇,命运给你回应
前端·后端·微信小程序
難釋懷17 分钟前
Nginx日志
前端·网络·nginx
Web极客码1 小时前
用 Python 搭建工具调用 Agent 的调试过程
java·服务器·前端
2401_881828321 小时前
简易文本处理网页工具|AI 通识课第三次作业
前端·javascript·html
Ai拆代码的曹操1 小时前
Dubbo 2.7.5 的线程上下文陷阱:从版本演进看 AllChannelHandler 的设计之痛
前端·dubbo·safari
障碍的枫子1 小时前
Vue组件导出&渲染
前端·javascript·vue.js
开开心心就好1 小时前
视频播放器完美解码集成三款播放器切换使用
前端·人工智能·智能手机·电脑·音视频·virtualenv·pygame
Sterting1 小时前
组件通信:Props 与 Emit
前端·vue.js
东方老白1 小时前
iOS 面试题
前端