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

相关推荐
万岳科技系统开发7 分钟前
智慧医院小程序开发推动医疗服务流程全面线上化
大数据·开发语言·人工智能
一只小灿灿9 分钟前
C++ 修饰符全面详解
开发语言·c++
马里马里奥-11 分钟前
从零搭建AI Agent工具链的技术文章大纲
开发语言·qt
耳东小鹿16 分钟前
对象常用方法
前端
程序员海军18 分钟前
一个 AI 应用开发程序员的一天,都在屏幕前忙些什么?
前端·后端·程序员
程序员黑豆40 分钟前
鸿蒙应用开发:Stack堆叠组件实战——实现微信消息角标效果
前端·harmonyos
夏幻灵1 小时前
浏览器原理深度解析:从输入 URL 到页面展现的全流程剖析
前端
不做Java程序猿好多年1 小时前
Java中 String、StringBuffer、StringBuilder 的区别详解
开发语言·python
会周易的程序员1 小时前
js-shm: 高性能 Node.js 共享内存模块
开发语言·javascript·c++·node.js·共享内存·shm
闲猫1 小时前
Agent工程实践:从WorkFlow到多Agent协作的落地笔记
java·服务器·前端