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

相关推荐
程序 代码狂人3 分钟前
经典 SQL 面试题:连续登录问题的两种经典解法
java·开发语言·算法
门思科技5 分钟前
ThinkLink 触发模型与告警规则实战:数据一小时才来一次,告警怎么做到不迟到、不刷屏、找对人
前端·后端
hunter_07619 分钟前
从零读懂 SwiftUI 新拖放 API:用 Apple 的纸牌示例理解排序、多项拖拽与移动规则
前端
时间的情敌24 分钟前
Electron 设置-webkit-app-region: drag;实现拖拽后, 无法响应鼠标划过事件及点击事件的解决方式
前端·vue.js
程序猿阿森1 小时前
深入解析 NLI:RAG 与大模型防幻觉的“最后一道防线”
前端·人工智能·算法
星夜离尘561 小时前
MATLAB 只剩批次摘要怎么合并方差:用 n、mean、M2 保留批间差异
开发语言·matlab
yuniko-n1 小时前
【JUC】JMM(Java 内存模型)
java·开发语言
Elastic 中国社区官方博客2 小时前
Observability:当 YAML 遇上 IConfiguration:OpenTelemetry .NET SDK 的声明式配置
大数据·开发语言·elasticsearch·搜索引擎·全文检索·.net