手写一个Promise,彻底掌握异步原理

手写 Promise 实现

Promise 是 JavaScript 中处理异步操作的核心机制,手写一个简单的 Promise 有助于深入理解其原理。以下是一个基础的 Promise 实现:

javascript 复制代码
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

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

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

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

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };

    const promise2 = new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }

      if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }

      if (this.state === 'pending') {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }

  let called = false;
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      const then = x.then;
      if (typeof then === 'function') {
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          r => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

Promise 核心原理

状态管理:Promise 有三种状态(pending/fulfilled/rejected),状态一旦改变就不可逆。

异步处理:通过回调函数队列(onFulfilledCallbacks/onRejectedCallbacks)实现异步调用。

链式调用:then 方法返回新 Promise 实现链式调用,通过 resolvePromise 处理返回值。

错误处理:通过 try-catch 捕获执行器(executor)和回调函数中的错误。

m.gu.yourmey.com

m.ed.yourmey.com

m.bs.yourmey.com

m.ih.yourmey.com

m.ay.yourmey.com

m.aj.yourmey.com

m.an.yourmey.com

m.xp.yourmey.com

m.lw.yourmey.com

m.wb.yourmey.com

m.fc.yourmey.com

m.bs.yourmey.com

m.ub.yourmey.com

m.ri.yourmey.com

m.ce.yourmey.com

m.ta.yourmey.com

m.jn.yourmey.com

m.da.yourmey.com

m.nd.yourmey.com

m.yu.yourmey.com

m.fj.yourmey.com

m.dm.yourmey.com

m.sr.yourmey.com

m.rl.yourmey.com

m.hg.yourmey.com

m.fd.yourmey.com

m.ts.yourmey.com

m.kn.yourmey.com

m.dg.yourmey.com

m.bq.yourmey.com

m.vj.yourmey.com

m.qk.yourmey.com

m.sd.yourmey.com

m.zm.yourmey.com

m.gt.yourmey.com

m.hs.yourmey.com

m.da.yourmey.com

m.eo.yourmey.com

m.su.yourmey.com

m.qk.yourmey.com

m.uo.yourmey.com

m.xo.yourmey.com

m.tx.yourmey.com

m.dt.yourmey.com

m.ju.yourmey.com

m.ai.yourmey.com

m.ra.yourmey.com

m.wk.yourmey.com

m.wh.yourmey.com

m.bh.yourmey.com

m.tg.yourmey.com

m.xk.yourmey.com

m.yu.yourmey.com

m.af.yourmey.com

m.ln.yourmey.com

m.ln.yourmey.com

m.el.yourmey.com

m.sb.yourmey.com

m.yf.yourmey.com

m.is.yourmey.com

m.xz.yourmey.com

m.oc.yourmey.com

m.ro.yourmey.com

m.gf.yourmey.com

m.tp.yourmey.com

m.fk.yourmey.com

m.wh.yourmey.com

m.up.yourmey.com

m.ki.yourmey.com

m.rt.yourmey.com

m.vo.yourmey.com

m.hw.yourmey.com

m.em.yourmey.com

m.sg.yourmey.com

m.jr.yourmey.com

m.zf.yourmey.com

m.jw.yourmey.com

m.jd.yourmey.com

m.yh.yourmey.com

m.ow.yourmey.com

m.ny.yourmey.com

m.rk.yourmey.com

m.rn.yourmey.com

m.dm.yourmey.com

m.dx.yourmey.com

m.fn.yourmey.com

m.xc.yourmey.com

m.yq.yourmey.com

m.ju.yourmey.com

m.aj.yourmey.com

m.ao.yourmey.com

m.pe.yourmey.com

m.ll.yourmey.com

m.af.yourmey.com

m.tg.yourmey.com

m.tj.yourmey.com

m.wq.yourmey.com

m.hr.yourmey.com

m.zz.yourmey.com

m.jr.yourmey.com

m.za.yourmey.com

m.we.yourmey.com

m.fs.yourmey.com

m.rx.yourmey.com

m.if.yourmey.com

m.ou.yourmey.com

m.pt.yourmey.com

m.mk.yourmey.com

m.fx.yourmey.com

m.ht.yourmey.com

m.oa.yourmey.com

m.yz.yourmey.com

m.al.yourmey.com

m.nq.yourmey.com

m.ee.yourmey.com

m.iz.yourmey.com

m.wb.yourmey.com

m.tv.yourmey.com

m.lf.yourmey.com

m.uo.yourmey.com

m.ik.yourmey.com

m.py.yourmey.com

m.ip.yourmey.com

m.sw.yourmey.com

m.al.yourmey.com

m.nx.yourmey.com

m.cg.yourmey.com

m.xq.yourmey.com

m.lw.yourmey.com

m.yg.yourmey.com

m.mr.yourmey.com

m.mw.yourmey.com

m.rw.yourmey.com

m.ce.yourmey.com

m.ae.yourmey.com

m.st.yourmey.com

m.hn.yourmey.com

m.wy.yourmey.com

m.pl.yourmey.com

m.io.yourmey.com

m.qd.yourmey.com

m.pn.yourmey.com

m.ou.yourmey.com

m.xz.yourmey.com

m.hw.yourmey.com

m.pb.yourmey.com

m.jx.yourmey.com

m.yb.yourmey.com

m.ac.yourmey.com

m.mv.yourmey.com

m.ao.yourmey.com

m.ey.yourmey.com

m.gp.yourmey.com

m.zx.yourmey.com

m.gd.yourmey.com

m.oi.yourmey.com

m.jt.yourmey.com

m.da.yourmey.com

m.qu.yourmey.com

m.mn.yourmey.com

m.ja.yourmey.com

m.pn.yourmey.com

m.nw.yourmey.com

m.vp.yourmey.com

m.uo.yourmey.com

m.lu.yourmey.com

m.dj.yourmey.com

m.gk.yourmey.com

m.sd.yourmey.com

m.rn.yourmey.com

m.ae.yourmey.com

m.im.yourmey.com

m.qx.yourmey.com

m.mk.yourmey.com

m.jo.yourmey.com

m.sk.yourmey.com

m.fx.yourmey.com

m.wx.yourmey.com

m.ao.yourmey.com

m.xl.yourmey.com

m.ka.yourmey.com

m.xt.yourmey.com

m.ld.yourmey.com

m.ko.yourmey.com

m.qp.yourmey.com

m.qf.yourmey.com

m.km.yourmey.com

m.qo.yourmey.com

m.fe.yourmey.com

m.iu.yourmey.com

m.jz.yourmey.com

m.id.yourmey.com

m.ce.yourmey.com

m.xa.yourmey.com

m.hp.yourmey.com

m.an.yourmey.com

m.py.yourmey.com

m.mp.yourmey.com

m.vg.yourmey.com

m.mx.yourmey.com

使用方法示例

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

p.then(res => {
  console.log(res);
  return 'chain';
}).then(res => {
  console.log(res);
});

关键实现点

微任务模拟:使用 setTimeout 模拟微任务队列(实际 Promise 使用微任务)。

值穿透:then 方法的参数如果不是函数,需要实现值穿透。

循环引用检测:防止 thenable 对象返回自身导致无限循环。

这个实现涵盖了 Promise 的核心功能,包括状态管理、异步处理、链式调用和错误处理机制。实际使用中建议直接使用原生 Promise,这个实现主要用于学习原理。

相关推荐
ClouGence1 小时前
Web 自动化测试总是超时?聊聊等待、超时和异步加载
前端·测试
RobinDevNotes2 小时前
从 Electron 到 GPUI,9 个跨平台桌面方案该怎么选
前端·javascript·rust·electron·openresty·前端开发工具
程序员大阳3 小时前
HTML+CSS+JS对话式实战(6)-学生端查看活动功能开发
javascript·css·html·模块·查看学生
jay神3 小时前
基于 YOLOv8 的轴承缺陷检测(Web 版)
前端·人工智能·yolo
jay神3 小时前
基于 YOLOv8 的森林火灾检测系统(Web 版)
前端·yolo
code2cat3 小时前
HTML基础篇之第一张网页:从index.html到浏览器里的任务清单
前端·html
噢,我明白了4 小时前
JAVA中的一些基础应用知识点
java·开发语言
miss4 小时前
AI 改完不敢上线?OpenSpec 规约驱动开发实战
前端·代码规范·前端工程化
AiMan4 小时前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真5 小时前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent