在手写 Promise 构造函数一文中,我们已经搭建了 Promise 的基本结构。本文将深入探讨 Promise 的核心------then
方法的实现。在面试中,能否写出符合规范的 then
方法往往是区分开发者对 Promise 理解深浅的关键。让我们沿着 Promise A+ 规范的要求,逐步实现一个完整的 then
方法。
then 方法的基本要求
在开始编码之前,我们需要明确 then
方法的几个核心特性:
- 原型方法 :
then
是 Promise 原型上的方法,且不可枚举 - 参数处理 :接收两个可选参数(
onFulfilled
和onRejected
),均为函数类型 - 链式调用:必须返回一个新的 Promise 实例,支持链式调用
- 调用限制:必须通过 Promise 实例调用,直接通过原型调用会报错
基于这些要求,我们可以搭建出 then
方法的基本框架:
js
(function () {
"use strict";
// 状态常量定义
var PENDING = "pending";
var FULFILLED = "fulfilled";
var REJECTED = "rejected";
function Promise(executor) {
// 构造函数实现(详见上篇文章)
}
var prototype = Promise.prototype;
// 定义对象属性的配置项(不可枚举)
function definePropertyConfig(object, key, value) {
Object.defineProperty(object, key, {
value: value,
writable: true,
enumerable: false,
configurable: true,
});
}
// 添加 Symbol.toStringTag 属性(增强调试体验)
if (typeof Symbol !== "undefined") {
definePropertyConfig(prototype, Symbol.toStringTag, "Promise");
}
// 检查调用者是否为 Promise 实例
function checkPromiseInstance(value) {
if (!(value instanceof Promise)) {
throw new TypeError(
"Method Promise.prototype.then called on incompatible receiver #<Promise>"
);
}
}
// 定义 then 方法
definePropertyConfig(prototype, "then", function (onFulfilled, onRejected) {
checkPromiseInstance(this);
var self = this;
return new Promise(function (resolve, reject) {
// 具体实现将在下文展开
});
});
})();
处理异步场景
当 Promise 处于异步操作中时(状态为 pending
),我们需要将回调函数存储起来,待状态改变后再执行:
js
function Promise(executor) {
var self = this;
self.state = PENDING;
self.result = void 0;
self.onFulfilledCallbacks = []; // 存储成功回调
self.onRejectedCallbacks = []; // 存储失败回调
// 状态转换函数
var changeState = function (state, value) {
if (self.state !== PENDING) return;
self.state = state;
self.result = value;
var callbacks = state === FULFILLED
? self.onFulfilledCallbacks
: self.onRejectedCallbacks;
// 异步执行所有存储的回调
setTimeout(function () {
callbacks.forEach(function (callback) {
typeof callback === "function" && callback(self.result);
});
});
};
var resolve = function (value) {
changeState(FULFILLED, value);
};
var reject = function (reason) {
changeState(REJECTED, reason);
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
在 then 方法中对应处理 pending 状态:
js
definePropertyConfig(prototype, "then", function (onFulfilled, onRejected) {
checkPromiseInstance(this);
var self = this;
return new Promise(function (resolve, reject) {
if (self.state === FULFILLED) {
// 处理已完成状态
} else if (self.state === REJECTED) {
// 处理已拒绝状态
} else {
// 存储回调,等待状态改变
self.onFulfilledCallbacks.push(function () {
onFulfilled(self.result);
});
self.onRejectedCallbacks.push(function () {
onRejected(self.result);
});
}
});
});
异步执行与错误处理
根据 Promise A+ 规范,then 的回调应该异步执行。我们使用 setTimeout
来模拟微任务队列:
js
definePropertyConfig(prototype, "then", function (onFulfilled, onRejected) {
checkPromiseInstance(this);
var self = this;
// 统一处理回调函数
function handleCallback(value, callback, resolve, reject) {
setTimeout(function () {
try {
var result = callback(value);
resolve(result); // 暂时简单处理
} catch (error) {
reject(error); // 捕获同步错误
}
}, 0);
}
return new Promise(function (resolve, reject) {
if (self.state === FULFILLED) {
handleCallback(self.result, onFulfilled, resolve, reject);
} else if (self.state === REJECTED) {
handleCallback(self.result, onRejected, resolve, reject);
} else {
self.onFulfilledCallbacks.push(function (value) {
handleCallback(value, onFulfilled, resolve, reject);
});
self.onRejectedCallbacks.push(function (value) {
handleCallback(value, onRejected, resolve, reject);
});
}
});
});
实现值穿透特性
值穿透是指在 Promise 链中.then
方法没有提供相应的回调函数(onFulfilled
或者onRejected
)或者不是一个函数类型,Promise会自动创建一个回调函数将这个值传递下去。
js
definePropertyConfig(prototype, "then", function (onFulfilled, onRejected) {
checkPromiseInstance(this);
var self = this;
// 值穿透处理
onFulfilled = typeof onFulfilled === "function"
? onFulfilled
: function (value) { return value; }; // 传递值
onRejected = typeof onRejected === "function"
? onRejected
: function (reason) { throw reason; }; // 抛出异常
// 其余代码保持不变
});
完整代码
js
(function () {
"use strict";
var PENDING = "pending";
var FULFILLED = "fulfilled";
var REJECTED = "rejected";
function Promise(executor) {
var self = this;
// 参数校验
if (typeof executor !== "function") {
throw new TypeError(`Promise resolver ${executor} is not a function`);
}
if (!(self instanceof Promise)) {
throw new TypeError("Promise constructor must be called with 'new'");
}
self.state = PENDING;
self.result = void 0;
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
var changeState = function (state, value) {
if (self.state !== PENDING) return;
self.state = state;
self.result = value;
var callbacks = state === FULFILLED
? self.onFulfilledCallbacks
: self.onRejectedCallbacks;
setTimeout(function () {
callbacks.forEach(function (callback) {
typeof callback === "function" && callback(self.result);
});
});
};
var resolve = function (value) {
changeState(FULFILLED, value);
};
var reject = function (reason) {
changeState(REJECTED, reason);
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
var prototype = Promise.prototype;
function definePropertyConfig(object, key, value) {
Object.defineProperty(object, key, {
value: value,
writable: true,
enumerable: false,
configurable: true,
});
}
function checkPromiseInstance(value) {
if (!(value instanceof Promise)) {
throw new TypeError(
"Method Promise.prototype.then called on incompatible receiver #<Promise>"
);
}
}
definePropertyConfig(prototype, "then", function (onFulfilled, onRejected) {
checkPromiseInstance(this);
var self = this;
// 值穿透处理
onFulfilled = typeof onFulfilled === "function"
? onFulfilled
: function (value) { return value; };
onRejected = typeof onRejected === "function"
? onRejected
: function (reason) { throw reason; };
function handleCallback(value, callback, resolve, reject) {
setTimeout(function () {
try {
var result = callback(value);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
}
return new Promise(function (resolve, reject) {
if (self.state === FULFILLED) {
handleCallback(self.result, onFulfilled, resolve, reject);
} else if (self.state === REJECTED) {
handleCallback(self.result, onRejected, resolve, reject);
} else {
self.onFulfilledCallbacks.push(function (value) {
handleCallback(value, onFulfilled, resolve, reject);
});
self.onRejectedCallbacks.push(function (value) {
handleCallback(value, onRejected, resolve, reject);
});
}
});
});
// 环境检测与导出
if (typeof window !== "undefined") {
window.SelfPromise = Promise;
}
if (typeof module === "object" && typeof module.exports === "object") {
module.exports = Promise;
}
})();
小结
本文详细实现了 Promise 的 then 方法,涵盖了:
- 基本结构:正确的原型方法定义和链式调用
- 状态处理:针对不同状态(fulfilled/rejected/pending)采取不同的处理策略
- 异步执行:使用 setTimeout 模拟微任务队列
- 错误处理:妥善处理回调函数中的同步错误
- 值穿透:实现参数非函数时的默认行为
这个实现已经涵盖了 Promise then 方法的核心功能,但需要注意的是,真正的 Promise 实现还需要处理更复杂的情况,如 thenable 对象的递归解析、循环引用检测等。这些内容我们将在后续文章中继续探讨。
通过手写实现,我们不仅能够更深入地理解 Promise 的工作原理,也能够在面试中展现出对 JavaScript 异步编程的深刻理解。