理解 Promise 的核心在于理解它是一个状态机和回调队列的集合。为了达到“去粗取精”的效果,我们不需要实现完整的 Promises/A+ 规范(那过于冗长),而是抓住其并发控制和状态流转的本质逻辑。
以下是 Promise 最核心的几个静态方法及构造逻辑的精简实现:
1. 核心机制:Promise.all
这是面试和实战中最常见的逻辑。它的精髓在于:并行执行,串行等待,一错全错。
JavaScript
Promise.myAll = function(promises) {
return new Promise((resolve, reject) => {
const results = [];
let count = 0;
const len = promises.length;
if (len === 0) return resolve([]);
promises.forEach((p, i) => {
// 包装成 Promise 以处理非 Promise 值
Promise.resolve(p).then(
res => {
results[i] = res; // 保证结果顺序
count++;
if (count === len) resolve(results);
},
err => reject(err) // 只要有一个失败,整体立即失败
);
});
});
};
2. 竞速机制:Promise.race
它的逻辑最纯粹:谁先完成(无论成功失败),就用谁的结果。
JavaScript
Promise.myRace = function(promises) {
return new Promise((resolve, reject) => {
promises.forEach(p => {
// 第一个改变状态的 Promise 会直接触发外层 Promise 的 resolve/reject
Promise.resolve(p).then(resolve, reject);
});
});
};
3. 容错机制:Promise.allSettled
与 all 不同,它不关心胜负,只关心“是否结束”。这在需要获取所有异步结果(无论好坏)时非常有用。
JavaScript
Promise.myAllSettled = function(promises) {
return Promise.all(
promises.map(p =>
Promise.resolve(p).then(
value => ({ status: 'fulfilled', value }),
reason => ({ status: 'rejected', reason })
)
)
);
};
4. 健壮性:Promise.any
这是“全败才败,一胜即胜”的逻辑。
JavaScript
Promise.myAny = function(promises) {
return new Promise((resolve, reject) => {
let count = 0;
const errors = [];
const len = promises.length;
if (len === 0) return reject(new AggregateError('All promises were rejected'));
promises.forEach((p, i) => {
Promise.resolve(p).then(
res => resolve(res), // 只要有一个成功,直接返回
err => {
errors[i] = err;
count++;
if (count === len) reject(new AggregateError(errors));
}
);
});
});
};
5. 状态机本质:简易构造器
如果要理解 Promise 内部是如何工作的,看这段极简的构造逻辑即可:
JavaScript
function MyPromise(executor) {
this.state = 'pending';
this.value = null;
this.callbacks = []; // 存储 then 里的回调
const resolve = (val) => {
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.value = val;
this.callbacks.forEach(cb => cb.onFulfilled(val));
};
const reject = (reason) => {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.value = reason;
this.callbacks.forEach(cb => cb.onRejected(reason));
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
总结
-
all: 所有人必须成功,一个失败就完蛋。
-
race: 只看第一名,不问对错。
-
allSettled: 所有人报个平安(无论死活)。
-
any: 只要有一个活着的就行,全死了才放弃。
这些逻辑的共性在于通过闭包维护计数器(Counter)或者直接竞争状态槽。掌握了这几个,就掌握了异步流控制的本质。
如果你对某个特定的并发控制(比如带并发限制的 Promise 调度器)感兴趣,我可以继续为你解构。你想了解如何控制异步任务的并发频率吗?