在 JavaScript 中,Promise 是一种用于处理异步操作的对象,它提供了一种更优雅的方式来处理异步代码,避免了回调地狱的问题。下面是对 JS 的 Promise 源码的详细解析:
一、Promise 的基本结构
一个 Promise 对象主要包含以下几个部分:
- 状态:Promise 有三种状态,分别是 pending(等待中)、fulfilled(已成功)和 rejected(已失败)。初始状态为 pending,一旦状态确定就不可再改变。
- 值:当 Promise 状态变为 fulfilled 时,会有一个值与之对应;当状态变为 rejected 时,会有一个原因(reason)与之对应。
- 回调函数队列:分别用于存储当 Promise 状态变为 fulfilled 或 rejected 时要执行的回调函数。
以下是一个简单的 Promise 实现框架:
function Promise(executor) {let self = this;self.status = 'pending';self.value = undefined;self.reason = undefined;self.onResolvedCallbacks = [];self.onRejectedCallbacks = [];function resolve(value) {if (self.status === 'pending') {self.status = 'fulfilled';self.value = value;self.onResolvedCallbacks.forEach(fn => fn());}}function reject(reason) {if (self.status === 'pending') {self.status = 'rejected';self.reason = reason;self.onRejectedCallbacks.forEach(fn => fn());}}try {executor(resolve, reject);} catch (e) {reject(e);}
}
在这个框架中,executor
是一个函数,它在 Promise 被创建时立即执行。executor
接受两个参数,分别是 resolve
和 reject
函数,用于在异步操作成功时调用 resolve
改变 Promise 的状态为 fulfilled
,并传入结果值;在异步操作失败时调用 reject
改变 Promise 的状态为 rejected
,并传入失败原因。
二、then 方法的实现
then
方法是 Promise 最重要的方法之一,它用于注册当 Promise 状态改变时要执行的回调函数,并返回一个新的 Promise 对象,以便实现链式调用。
Promise.prototype.then = function(onFulfilled, onRejected) {let self = this;let promise2;onFulfilled = typeof onFulfilled === 'function'? onFulfilled : value => value;onRejected = typeof onRejected === 'function'? onRejected : reason => { throw reason };if (self.status === 'fulfilled') {return promise2 = new Promise((resolve, reject) => {try {let x = onFulfilled(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}});}if (self.status === 'rejected') {return promise2 = new Promise((resolve, reject) => {try {let x = onRejected(self.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}});}if (self.status === 'pending') {return promise2 = new Promise((resolve, reject) => {self.onResolvedCallbacks.push(() => {try {let x = onFulfilled(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}});self.onRejectedCallbacks.push(() => {try {let x = onRejected(self.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}});});}
};
在 then
方法中,首先判断当前 Promise 的状态,如果是 fulfilled 或 rejected,则立即执行相应的回调函数,并通过 resolvePromise
函数处理回调函数的返回值,确保返回一个新的 Promise 对象。如果当前状态是 pending,则将回调函数存储在相应的队列中,等待状态改变时执行。
三、resolvePromise 函数的实现
resolvePromise
函数用于处理then方法中回调函数的返回值,确保 Promise 的链式调用正确工作。
function resolvePromise(promise2, x, resolve, reject) {let then;let thenCalledOrThrow = false;if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise!'));}if (x instanceof Promise) {if (x.status === 'pending') {x.then(function(value) {resolvePromise(promise2, value, resolve, reject);}, reject);} else {x.then(resolve, reject);}return;}if ((x!== null) && ((typeof x === 'object') || (typeof x === 'function'))) {try {then = x.then;if (typeof then === 'function') {then.call(x, function(y) {if (thenCalledOrThrow) return;thenCalledOrThrow = true;return resolvePromise(promise2, y, resolve, reject);}, function(r) {if (thenCalledOrThrow) return;thenCalledOrThrow = true;return reject(r);});} else {resolve(x);}} catch (e) {if (thenCalledOrThrow) return;thenCalledOrThrow = true;return reject(e);}} else {resolve(x);}
}
这个函数主要处理了以下几种情况:
- 如果返回值是自身,则抛出类型错误,因为不允许出现循环引用。
- 如果返回值是另一个 Promise,则根据其状态进行处理。
- 如果返回值是一个对象或函数,则尝试调用其then方法,如果存在的话。如果没有
then
方法,则直接将其值作为新 Promise 的结果。
四、catch 方法的实现
catch方法用于注册当 Promise 被拒绝时要执行的回调函数。
Promise.prototype.catch = function(onRejected) {return this.then(null, onRejected);
};
它实际上是调用 then
方法,并只传递拒绝回调函数。