TypechoJoeTheme

至尊技术网

统计
登录
用户名
密码

手写Promise核心原理及源码实现

2025-11-14
/
0 评论
/
1 阅读
/
正在检测是否收录...
11/14

在现代JavaScript开发中,Promise已经成为处理异步操作的基石。无论是网络请求、定时器回调,还是复杂的异步流程控制,我们都离不开它的身影。然而,很多开发者只是“会用”Promise,却对其内部机制一知半解。本文将带你从零开始,深入剖析Promise的核心原理,并手写一个符合规范的简易Promise实现。


Promise的本质:状态机与回调管理

Promise本质上是一个状态机,它有三种状态:pending(等待)、fulfilled(成功)和rejected(失败)。一旦状态从pending变为fulfilledrejected,就不可逆,这保证了Promise的确定性。

当我们调用new Promise(executor)时,传入的executor函数会立即执行。这个函数接收两个参数:resolvereject,用于改变Promise的状态。例如:

js const p = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); }, 1000); });

这里的resolve('success')会将Promise状态从pending变为fulfilled,并保存结果值。而reject同理,用于表示失败。


实现Promise的基本结构

我们从最基础的框架开始构建自己的MyPromise类:

js
class MyPromise {
constructor(executor) {
this.status = 'pending';
this.value = undefined;
this.reason = undefined;

const resolve = (value) => {
  if (this.status === 'pending') {
    this.status = 'fulfilled';
    this.value = value;
  }
};

const reject = (reason) => {
  if (this.status === 'pending') {
    this.status = 'rejected';
    this.reason = reason;
  }
};

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

}
}

这里我们定义了状态、值和错误原因,并确保状态只能改变一次。同时,executor可能抛出异常,我们需要用try-catch捕获并转为reject


then方法的实现:链式调用与异步执行

then是Promise最核心的方法,它接收两个回调:onFulfilledonRejected。关键点在于:

  1. then必须返回一个新的Promise,以支持链式调用;
  2. 回调必须异步执行,即使Promise已经完成,也要通过微任务队列延迟执行;
  3. 支持穿透传递,即不传回调时应将值或错误继续向下传递。

为了实现异步执行,我们可以使用queueMicrotask模拟微任务:

js
then(onFulfilled, onRejected) {
// 处理可选参数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };

return new MyPromise((resolve, reject) => {
if (this.status === 'fulfilled') {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(x, resolve, reject);
} catch (e) {
reject(e);
}
});
}

if (this.status === 'rejected') {
  queueMicrotask(() => {
    try {
      const x = onRejected(this.reason);
      resolvePromise(x, resolve, reject);
    } catch (e) {
      reject(e);
    }
  });
}

if (this.status === 'pending') {
  // 存储回调,等待状态变更
  this.onResolvedCallbacks.push(() => {
    queueMicrotask(() => {
      try {
        const x = onFulfilled(this.value);
        resolvePromise(x, resolve, reject);
      } catch (e) {
        reject(e);
      }
    });
  });

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

});
}

注意,当状态为pending时,我们需要将回调缓存起来,等到resolvereject被调用时再执行。


处理返回值:resolvePromise函数

如果then的回调返回的是另一个Promise,我们需要等待其结果。为此,我们实现一个resolvePromise函数来统一处理各种返回值类型:

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

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/A+规范中关于“解决过程”的复杂逻辑,包括循环引用检测、对象/函数判断、thenable对象处理等。


完善功能:静态方法与异常处理

除了then,我们还可以实现catchfinally以及Promise.resolvePromise.reject等静态方法:

js
static resolve(value) {
return new MyPromise(resolve => resolve(value));
}

static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}

这些方法极大提升了使用的便利性。


通过以上步骤,我们实现了一个基本符合Promise/A+规范的Promise类。虽然省略了部分边界情况,但核心逻辑清晰完整。理解这一过程,不仅能加深对异步编程的理解,也为学习更高级的异步模式(如async/await)打下坚实基础。

PromiseJavaScript异步编程then方法微任务队列手写PromisePromise源码状态机
朗读
赞(0)
版权属于:

至尊技术网

本文链接:

https://www.zzwws.cn/archives/38567/(转载时请注明本文出处及文章链接)

评论 (0)

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月

最新回复

  1. 强强强
    2025-04-07
  2. jesse
    2025-01-16
  3. sowxkkxwwk
    2024-11-20
  4. zpzscldkea
    2024-11-20
  5. bruvoaaiju
    2024-11-14

标签云