手写一个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,这个实现主要用于学习原理。

相关推荐
moonrailgun6 分钟前
用 Node.js 复刻 Codex Astra 的终端星光
前端·javascript·算法
君顾113 分钟前
本地折扣卡 CPS 平台搭建:从系统架构到落地实战
java·开发语言·折扣卡
海上彼尚24 分钟前
Cursor 模型的强度实测排行
前端·人工智能·后端
默_笙31 分钟前
💫 给金鱼建图书馆(下):Milvus 向量数据库,让 AI 拥有长期记忆
前端·javascript
liangshanbo12151 小时前
手写 Function.prototype.call 与 Function.prototype.apply 面试题满分答案
开发语言·javascript·原型模式
Zenova EdgeOS1 小时前
C++ 工业边缘 libcurl HTTP 客户端实战
开发语言·c++·网络协议·边缘计算
EatFan1 小时前
HTML前端利用flex解决input定位的问题
前端·css·html·css3
Jackson_GJH2 小时前
Qt 右键自定义菜单的实现
开发语言·c++·qt
CoderYanger2 小时前
前端基础——JavaScript(WebAPI)(下篇)
java·开发语言·前端·javascript·程序人生·面试·职场和发展
kyriewen2 小时前
AI 改祖传模块后,代码评审总绕不开两个问题
前端·程序员·ai编程