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

相关推荐
5008432 分钟前
React Native for OpenHarmony 实战:三方库 react-native-device-uptime 的鸿蒙化适配指南
javascript·分布式·react native·react.js·harmonyos
孙启超1 小时前
【AI开发之Rust】第 22 课:一键多平台与工程收尾 —— CI、发布检查与结课
开发语言·后端·rust
admin and root8 小时前
「AI安全篇」实战AntiDebug自动化JS逆向加解密MCP
javascript·人工智能·网络安全·自动化·漏洞挖掘·cnvd·src赏金
落魄实习生9 小时前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
前端snow9 小时前
ai agent --- postgreSQL 关系型数据库
前端
茉莉玫瑰花茶9 小时前
GO [ 方法 ]
开发语言·后端·golang
卷无止境10 小时前
ECharts:把数据变成故事的可视化利器
前端
Eric_见嘉10 小时前
在职前端 Skill 和 MCP 分享
前端·后端·agent
狗凯之家源码网10 小时前
微博图床 PHP 系统搭建与实战应用指南
android·开发语言·php
liangshanbo121510 小时前
面试题:如何优化 Webpack 的打包速度?
前端·webpack·node.js