本专栏聚焦Promise的核心原理与高级应用,包含: ✓ Promise A+规范深度解读 ✓ 手写实现与源码分析 ✓ 异步编程设计模式 ✓ 性能调优与错误处理
适合有JavaScript基础,希望深入异步编程的开发者。我们将用最少的篇幅,讲透最核心的知识。
引言
在前面的文章中,我们详细讲解了Promise的核心原理及相关的方法,本文将从零开始,手写一个功能完整的Promise类,深入理解Promise的工作原理。
Promise核心概念回顾
在开始实现之前,我们先回顾一下Promise的核心特性:
- 三种状态:pending(等待)、fulfilled(已成功)、rejected(已失败)。
- 状态不可逆:一旦状态改变,就不能再变。
- 链式调用:then方法返回一个新的Promise。
- 异步执行:回调函数总是异步执行。
- 错误冒泡:错误会一直向后传递,直到被捕获。
基础骨架实现
构造函数
代码实现
javascript
class Promise {
// 构造函数接收一个执行器函数executor
constructor(executor) {
this.promiseState = 'pending'; // 声明初始状态
this.promiseResult = null; // Priomise结果
// 存储成功和失败的回调函数
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
// 声明resolve和reject两个函数
const resolve = (value) => {
// 判断状态是否为pending
if (this.promiseState !== 'pending') return;
// 1、修改对象状态
this.promiseState = 'fulfilled';
// 2、保存成功值
this.promiseResult = value;
// 3、调用成功回调函数
if (this.onResolvedCallbacks.length > 0) {
this.onResolvedCallbacks.forEach(item => item(value));
}
}
const reject = (reason) => {
// 判断状态是否为pending
if (this.promiseState !== 'pending') return;
// 1、修改对象状态
this.promiseState = 'rejected';
// 2、保存失败原因
this.promiseResult = reason;
// 3、调用失败回调函数
if (this.onRejectedCallbacks.length > 0) {
this.onRejectedCallbacks.forEach(item => item(reason));
}
}
try {
// 执行器函数executor是同步调用
executor(resolve, reject);
}
catch (e) {
// 执行器抛出的异常直接reject
reject(e);
}
}
}
关键点解析
- 状态机:使用promiseState记录当前状态,当状态不为'pending'时,说明状态已经改变过了,直接返回,不进行任何处理;否则,才进行修改状态、保存结果、执行调用等操作。
- 结果存储:promiseResult存储成功值或失败原因。
- 回调队列:维护成功和失败回调队列,支持多次then调用。
- 异步执行:使用setTimeout确保回调异步执行。
链式调用核心实现
then()方法的基本结构
代码实现
javascript
then(onResolved, onRejected) {
// 如果不是函数则创建一个默认函数
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 返回新的Promise
const promise2 = new Promise((resolve, reject) => {
// 处理resolved状态的函数
const handleResolved = () => {
// 使用setTimeout确保异步执行
setTimeout(() => {
try {
const x = onResolved(this.promiseResult);
// 处理返回值,可能是普通值或Promise
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
};
// 处理rejected状态的函数
const handleRejected = () => {
setTimeout(() => {
try {
const x = onRejected(this.promiseResult);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
};
// 根据当前状态处理
if (this.promiseState === 'fulfilled') {
handleResolved();
} else if (this.promiseState === 'rejected') {
handleRejected();
} else if (this.promiseState === 'pending') {
// 如果是pending状态,将回调函数存储起来
this.onResolvedCallbacks.push(() => handleResolved());
this.onRejectedCallbacks.push(() => handleRejected());
}
});
return promise2;
}
关键点解析
- 值透传:如果
onResolved不是函数,创建一个返回原值的函数value => value。 - 错误冒泡:如果
onRejected不是函数,创建一个抛出错误的函数,让错误继续向下传递。 - 链式调用的基础:每个 then 必须返回新的 Promise,且返回的 Promise 是独立的,状态不受前一个 Promise 影响。
- 异步执行包装器(handleResolved/handleRejected):模拟微任务行为,确保回调函数总是异步执行。
Promise解析过程(核心难点)
代码实现
javascript
resolvePromise(promise2, x, resolve, reject) {
// 防止循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 标记是否已被调用,防止多次调用
let called = false;
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
// 获取then方法
const then = x.then;
if (typeof then === 'function') {
// 如果x有then方法,则将其视为Promise
then.call(
x,
// resolvePromise
y => {
if (called) return;
called = true;
// 递归解析
this.resolvePromise(promise2, y, resolve, reject);
},
// rejectPromise
r => {
if (called) return;
called = true;
reject(r);
}
);
} else {
// 如果x是普通对象或函数,直接resolve
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
// 如果x是基本类型,直接resolve
resolve(x);
}
}
为什么需要resolvePromise
- 防止循环引用导致的无限递归。
- 确保 Promise 解析过程符合规范。
这部分,我认为是 Promise 实现中最复杂的部分!
实例方法实现
catch()方法
代码实现
javascript
catch(onRejected) {
return this.then(null, onRejected);
}
finally()方法
代码实现
javascript
finally(onFinally) {
// 需要先检查 onFinally 是否为函数
if (typeof onFinally !== 'function') {
return this.then();
}
return this.then(
value => Promise.resolve(onFinally()).then(() => value),
reason => Promise.resolve(onFinally()).then(() => { throw reason })
);
}
静态方法实现
Promise.resolve() / Promise.reject()
代码实现
javascript
static resolve(value) {
// 如果已经是Promise实例,直接返回
if (value instanceof Promise) {
return value;
}
// 普通值
return new Promise(resolve => {
resolve(value);
});
}
// Promise静态方法reject
static reject(reason) {
return new Promise((_, reject) => {
reject(reason);
});
}
从上述代码中,我们可以看出:resolve() 方法比 reject() 方法多了一层判断逻辑,即:
如果已经是Promise实例,直接返回,这部分代码可以保障Promise.resolve()方法的幂等性。
Promise.all():所有成功,才算成功
代码实现
javascript
static all(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises) || promises.length === 0) {
return reject(new TypeError('参数必须是数组'));
}
const results = [];
let completedCount = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
value => {
results[index] = value;
completedCount++;
if (completedCount === promises.length) {
resolve(results);
}
},
reject // 直接传递reject函数
);
});
});
}
Promise.race():竞速,谁最先完成
代码实现
javascript
static race(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises) || promises.length === 0) {
return reject(new TypeError('参数必须是数组'));
}
promises.forEach(promise => {
Promise.resolve(promise).then(resolve, reject);
});
});
}
Promise.allSettled():全部完成,记录所有结果
代码实现
javascript
static allSettled(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises) || promises.length === 0) {
return reject(new TypeError('参数必须是数组'));
}
const results = [];
let completedCount = 0;
const processResult = (index, value, status) => {
results[index] = status === 'fulfilled'
? { status: 'fulfilled', value }
: { status: 'rejected', reason: value };
completedCount++;
if (completedCount === promises.length) {
resolve(results);
}
};
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
value => processResult(index, value, 'fulfilled'),
reason => processResult(index, reason, 'rejected')
);
});
});
}
Promise.any():任意一个成功,都算成功
代码实现
javascript
static any(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises) || promises.length === 0) {
return reject(new TypeError('参数必须是数组'));
}
const errors = [];
let rejectedCount = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
value => {
resolve(value);
},
reason => {
errors[index] = reason;
rejectedCount++;
if (rejectedCount === promises.length) {
reject(new AggregateError(errors, '所有Promise都被拒绝'));
}
}
);
});
});
}
完整代码
javascript
class Promise {
// 构造函数接收一个执行器函数executor
constructor(executor) {
this.promiseState = 'pending'; // 声明初始状态
this.promiseResult = null; // Priomise结果
// 存储成功和失败的回调函数
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
// 声明resolve和reject两个函数
const resolve = (value) => {
// 判断状态是否为pending
if (this.promiseState !== 'pending') return;
// 1、修改对象状态
this.promiseState = 'fulfilled';
// 2、保存成功值
this.promiseResult = value;
// 3、调用成功回调函数
if (this.onResolvedCallbacks.length > 0) {
this.onResolvedCallbacks.forEach(item => item(value));
}
}
const reject = (reason) => {
// 判断状态是否为pending
if (this.promiseState !== 'pending') return;
// 1、修改对象状态
this.promiseState = 'rejected';
// 2、保存失败原因
this.promiseResult = reason;
// 3、调用失败回调函数
if (this.onRejectedCallbacks.length > 0) {
this.onRejectedCallbacks.forEach(item => item(reason));
}
}
try {
// 执行器函数executor是同步调用
executor(resolve, reject);
}
catch (e) {
// 执行器抛出的异常直接reject
reject(e);
}
}
// then方法接收两个参数onResolved和onRejected
then(onResolved, onRejected) {
// 如果不是函数则创建一个默认函数
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 返回新的Promise
const promise2 = new Promise((resolve, reject) => {
// 处理resolved状态的函数
const handleResolved = () => {
// 使用setTimeout确保异步执行
setTimeout(() => {
try {
const x = onResolved(this.promiseResult);
// 处理返回值,可能是普通值或Promise
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
};
// 处理rejected状态的函数
const handleRejected = () => {
setTimeout(() => {
try {
const x = onRejected(this.promiseResult);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
};
// 根据当前状态处理
if (this.promiseState === 'fulfilled') {
handleResolved();
} else if (this.promiseState === 'rejected') {
handleRejected();
} else if (this.promiseState === 'pending') {
// 如果是pending状态,将回调函数存储起来
this.onResolvedCallbacks.push(() => handleResolved());
this.onRejectedCallbacks.push(() => handleRejected());
}
});
return promise2;
}
// 处理Promise解析过程
resolvePromise(promise2, x, resolve, reject) {
// 防止循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 标记是否已被调用,防止多次调用
let called = false;
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
// 获取then方法
const then = x.then;
if (typeof then === 'function') {
// 如果x有then方法,则将其视为Promise
then.call(
x,
// resolvePromise
y => {
if (called) return;
called = true;
// 递归解析
this.resolvePromise(promise2, y, resolve, reject);
},
// rejectPromise
r => {
if (called) return;
called = true;
reject(r);
}
);
} else {
// 如果x是普通对象或函数,直接resolve
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
// 如果x是基本类型,直接resolve
resolve(x);
}
}
// catch方法接收一个参数onRejected
catch(onRejected) {
return this.then(null, onRejected);
}
// finally方法接收一个参数onFinally
finally(onFinally) {
// 需要先检查 onFinally 是否为函数
if (typeof onFinally !== 'function') {
return this.then();
}
return this.then(
value => Promise.resolve(onFinally()).then(() => value),
reason => Promise.resolve(onFinally()).then(() => { throw reason })
);
}
// Promise静态方法resolve
static resolve(value) {
// 如果已经是Promise实例,直接返回
if (value instanceof Promise) {
return value;
}
// 普通值
return new Promise(resolve => {
resolve(value);
});
}
// Promise静态方法reject
static reject(reason) {
return new Promise((_, reject) => {
reject(reason);
});
}
// Promise静态方法all
static all(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises) || promises.length === 0) {
return reject(new TypeError('参数必须是数组'));
}
const results = [];
let completedCount = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
value => {
results[index] = value;
completedCount++;
if (completedCount === promises.length) {
resolve(results);
}
},
reject // 直接传递reject函数
);
});
});
}
// Promise静态方法race
static race(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises) || promises.length === 0) {
return reject(new TypeError('参数必须是数组'));
}
promises.forEach(promise => {
Promise.resolve(promise).then(resolve, reject);
});
});
}
// Promise静态方法allSettled
static allSettled(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises) || promises.length === 0) {
return reject(new TypeError('参数必须是数组'));
}
const results = [];
let completedCount = 0;
const processResult = (index, value, status) => {
results[index] = status === 'fulfilled'
? { status: 'fulfilled', value }
: { status: 'rejected', reason: value };
completedCount++;
if (completedCount === promises.length) {
resolve(results);
}
};
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
value => processResult(index, value, 'fulfilled'),
reason => processResult(index, reason, 'rejected')
);
});
});
}
// Promise静态方法any
static any(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises) || promises.length === 0) {
return reject(new TypeError('参数必须是数组'));
}
const errors = [];
let rejectedCount = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
value => {
resolve(value);
},
reason => {
errors[index] = reason;
rejectedCount++;
if (rejectedCount === promises.length) {
reject(new AggregateError(errors, '所有Promise都被拒绝'));
}
}
);
});
});
}
}
结语
本文通过手写实现Promise,深入理解了Promise的工作原理,掌握了异步编程的核心思想。虽然实际的Promise实现更为复杂(考虑更多边界情况和性能优化),但本文的实现已经涵盖了Promise的核心功能。对于文章中错误的地方或者有任何问题,欢迎在评论区留言讨论!