手写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);
// });
相关推荐
国思RDIF框架2 小时前
RDIFramework.NET Web 敏捷开发框架 V6.3 发布 (.NET8+、Framework 双引擎)
前端
Mintopia2 小时前
如何在有限的时间里,活出几倍的人生
前端
炫饭第一名2 小时前
速通Canvas指北🦮——变形、渐变与阴影篇
前端·javascript·程序员
Neptune12 小时前
让我带你迅速吃透React组件通信:从入门到精通(上篇)
前端·javascript
阿懂在掘金2 小时前
Vue 表单避坑(一):为什么 v-model 绑定对象属性会偷偷修改父组件数据?
前端·vue.js
小码哥_常2 小时前
Android与JS交互:解锁混合开发的魔法之门
前端
leafyyuki2 小时前
如何优雅地上传大文件?分片上传实战指南
前端·音视频开发
Mintopia2 小时前
现代 Vue 3 页面组件文件安排与通信实践
前端
只会cv的前端攻城狮2 小时前
兼容性地狱-Uniapp钉钉小程序环境隔离踩坑实录
前端·uni-app